<?php

namespace App\Auth\Controller;

use App\Auth\Entity\MobileVerificationOtp;
use App\Auth\Entity\User;
use App\Clinic\Repository\ClinicRepository;
use App\Doctor\Repository\DoctorRepository;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Controller\BaseController;
use App\Sms\Service\SmsService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
use Symfony\Component\Security\Http\Attribute\IsGranted;
use OpenApi\Attributes as OA;

#[OA\Tag(name: 'Auth')]
#[IsGranted('IS_AUTHENTICATED_FULLY')]
class NotificationMobileController extends BaseController
{
    public function __construct(
        private readonly EntityManagerInterface $em,
        private readonly DoctorRepository       $doctorRepo,
        private readonly ClinicRepository       $clinicRepo,
        private readonly SmsService             $smsService,
    ) {}

    // ── Request OTP ───────────────────────────────────────────────────────────

    #[Route('/api/v1/notification-mobile/request-otp', methods: ['POST'])]
    public function requestOtp(Request $request, #[CurrentUser] User $user): JsonResponse
    {
        $data   = json_decode($request->getContent(), true) ?? [];
        $target = trim((string) ($data['target'] ?? ''));
        $mobile = trim((string) ($data['new_mobile'] ?? ''));

        if (!in_array($target, ['doctor', 'clinic'], true)) {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'target باید doctor یا clinic باشد', 422);
        }
        if (!preg_match('/^09\d{9}$/', $mobile)) {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'شماره موبایل معتبر نیست (فرمت: 09XXXXXXXXX)', 422);
        }

        [$entity, $entityId] = $this->resolveEntity($target, $user);
        if ($entity === null) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'پروفایل یافت نشد', 404);
        }

        // حذف OTP های قبلی
        $this->em->createQuery('DELETE FROM App\Auth\Entity\MobileVerificationOtp o WHERE o.entityType = :t AND o.entityId = :id')
            ->setParameter('t', $target)
            ->setParameter('id', $entityId)
            ->execute();

        $otp = new MobileVerificationOtp($target, $entityId, $mobile);
        $this->em->persist($otp);
        $this->em->flush();

        // ارسال SMS
        $this->smsService->dispatchTemplate(
            \App\Sms\Entity\SmsLog::TAG_NOTIFICATION_MOBILE,
            $mobile,
            ['code' => $otp->getOtpCode()],
        );

        return $this->success([
            'message'    => 'کد تأیید ارسال شد',
            'expires_in' => 300,
        ]);
    }

    // ── Verify OTP ────────────────────────────────────────────────────────────

    #[Route('/api/v1/notification-mobile/verify', methods: ['POST'])]
    public function verify(Request $request, #[CurrentUser] User $user): JsonResponse
    {
        $data     = json_decode($request->getContent(), true) ?? [];
        $target   = trim((string) ($data['target'] ?? ''));
        $otpInput = trim((string) ($data['otp_code'] ?? ''));

        if (!in_array($target, ['doctor', 'clinic'], true)) {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'target باید doctor یا clinic باشد', 422);
        }

        [$entity, $entityId] = $this->resolveEntity($target, $user);
        if ($entity === null) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'پروفایل یافت نشد', 404);
        }

        /** @var MobileVerificationOtp|null $otp */
        $otp = $this->em->createQuery(
            'SELECT o FROM App\Auth\Entity\MobileVerificationOtp o
             WHERE o.entityType = :t AND o.entityId = :id AND o.isUsed = false
             ORDER BY o.createdAt DESC'
        )->setParameter('t', $target)
         ->setParameter('id', $entityId)
         ->setMaxResults(1)
         ->getOneOrNullResult();

        if ($otp === null) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'درخواست OTP یافت نشد. ابتدا کد را درخواست دهید', 404);
        }
        if ($otp->isExpired()) {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'کد تأیید منقضی شده. مجدداً درخواست دهید', 422);
        }
        if ($otp->getOtpCode() !== $otpInput) {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'کد تأیید اشتباه است', 422);
        }

        $otp->markUsed();
        $entity->setNotificationMobile($otp->getNewMobile());
        $this->em->flush();

        return $this->success([
            'notification_mobile' => $otp->getNewMobile(),
            'message'             => 'شماره اعلان با موفقیت ذخیره شد',
        ]);
    }

    // ── GET current notification mobile ──────────────────────────────────────

    #[Route('/api/v1/notification-mobile/{target}', methods: ['GET'], requirements: ['target' => 'doctor|clinic'])]
    public function getCurrent(string $target, #[CurrentUser] User $user): JsonResponse
    {
        [$entity] = $this->resolveEntity($target, $user);
        if ($entity === null) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'پروفایل یافت نشد', 404);
        }

        return $this->success([
            'notification_mobile' => $entity->getNotificationMobile(),
        ]);
    }

    // ── REMOVE notification mobile ────────────────────────────────────────────

    #[Route('/api/v1/notification-mobile/{target}', methods: ['DELETE'], requirements: ['target' => 'doctor|clinic'])]
    public function remove(string $target, #[CurrentUser] User $user): JsonResponse
    {
        [$entity] = $this->resolveEntity($target, $user);
        if ($entity === null) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'پروفایل یافت نشد', 404);
        }

        $entity->setNotificationMobile(null);
        $this->em->flush();

        return $this->success(['message' => 'شماره اعلان حذف شد']);
    }

    // ── Helper ────────────────────────────────────────────────────────────────

    private function resolveEntity(string $target, User $user): array
    {
        if ($target === 'doctor') {
            $entity = $this->doctorRepo->findByUser($user);
            return [$entity, $entity?->getId()];
        }
        $entity = $this->clinicRepo->findByUser($user);
        return [$entity, $entity?->getId()];
    }
}
