<?php

namespace App\Services;

use App\Models\Advertisement;
use App\Models\AdvertisementSplashImpression;
use Illuminate\Support\Facades\DB;

/**
 * إعلان شاشة كاملة عند فتح التطبيق — حد أقصى مرّتين لكل مستخدم في اليوم لكل إعلان.
 */
final class SplashAdService
{
    public const MAX_VIEWS_PER_DAY = 2;

    public function resolveForPatient(int $patientId): ?Advertisement
    {
        return $this->resolve('patient', $patientId, fn ($q) => $q->where(fn ($q) => $q->where('target', 'all')->orWhere('target', 'patients')));
    }

    public function resolveForDoctor(int $doctorId): ?Advertisement
    {
        return $this->resolve('doctor', $doctorId, fn ($q) => $q->where(fn ($q) => $q->where('target', 'all')->orWhere('target', 'doctors')));
    }

    /**
     * يحجز مشاهدة (يزيد العداد) ويعيد الإعلان إن بقي ضمن الحد اليومي.
     */
    private function resolve(string $role, int $viewerId, callable $targetScope): ?Advertisement
    {
        $candidates = Advertisement::query()
            ->active()
            ->where('display_mode', 'splash')
            ->tap($targetScope)
            ->where(function ($q) {
                $q->where(function ($q2) {
                    $q2->whereIn('media_type', ['image', 'gif'])
                        ->whereNotNull('image');
                })->orWhere(function ($q2) {
                    $q2->where('media_type', 'video')
                        ->whereNotNull('video_path');
                });
            })
            ->orderBy('sort_order')
            ->orderBy('id')
            ->get();

        foreach ($candidates as $ad) {
            if ($this->reserveViewSlot($ad->id, $role, $viewerId)) {
                return $ad;
            }
        }

        return null;
    }

    private function reserveViewSlot(int $advertisementId, string $role, int $viewerId): bool
    {
        $today = today()->toDateString();

        return (bool) DB::transaction(function () use ($advertisementId, $role, $viewerId, $today) {
            $row = AdvertisementSplashImpression::query()
                ->where('advertisement_id', $advertisementId)
                ->where('viewer_role', $role)
                ->where('viewer_id', $viewerId)
                ->whereDate('view_date', $today)
                ->lockForUpdate()
                ->first();

            $current = $row?->count ?? 0;

            if ($current >= self::MAX_VIEWS_PER_DAY) {
                return false;
            }

            if (! $row) {
                AdvertisementSplashImpression::create([
                    'advertisement_id' => $advertisementId,
                    'viewer_role'      => $role,
                    'viewer_id'        => $viewerId,
                    'view_date'        => $today,
                    'count'            => 1,
                ]);
            } else {
                $row->increment('count');
            }

            return true;
        });
    }
}
