<?php

namespace App\Billing\Controller;

use App\Auth\Entity\User;
use App\Billing\Entity\Claim;
use App\Billing\Repository\ClaimRepository;
use App\Billing\Repository\InvoiceRepository;
use App\Billing\Service\ClaimService;
use App\Billing\Service\InvoiceService;
use App\Clinic\Repository\ClinicRepository;
use App\Doctor\Repository\DoctorRepository;
use App\Patient\Repository\PatientSessionRepository;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Controller\BaseController;
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: 'Billing')]
#[IsGranted('IS_AUTHENTICATED_FULLY')]
class BillingController extends BaseController
{
    public function __construct(
        private readonly InvoiceService            $invoiceService,
        private readonly InvoiceRepository          $invoiceRepo,
        private readonly ClaimService               $claimService,
        private readonly ClaimRepository            $claimRepo,
        private readonly PatientSessionRepository   $sessionRepo,
        private readonly DoctorRepository           $doctorRepo,
        private readonly ClinicRepository           $clinicRepo,
    ) {}

    #[Route('/api/v1/billing/invoices', methods: ['POST'])]
    public function create(Request $request, #[CurrentUser] User $user): JsonResponse
    {
        [$entityType, $entityId] = $this->resolveEntity($user);
        if ($entityId === null) {
            return $this->error(ErrorCodes::ERR_FORBIDDEN_001, 'پروفایل یافت نشد', 403);
        }

        $data        = json_decode($request->getContent(), true) ?? [];
        $sessionUuid = trim($data['session_uuid'] ?? '');
        if ($sessionUuid === '') {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'session_uuid الزامی است', 422);
        }

        $session = $this->sessionRepo->findByUuid($sessionUuid);
        if ($session === null || !$this->ownsSession($session, $entityType, $entityId)) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'مراجعه یافت نشد', 404);
        }

        $invoice = $this->invoiceService->createFromSession($session, $entityType, $entityId);

        return $this->success(['data' => $invoice->toArray()], 201);
    }

    #[Route('/api/v1/billing/invoices/{uuid}', methods: ['GET'])]
    public function show(string $uuid, #[CurrentUser] User $user): JsonResponse
    {
        [$entityType, $entityId] = $this->resolveEntity($user);
        $invoice = $this->invoiceRepo->findByUuid($uuid);
        if ($invoice === null || $invoice->getEntityType() !== $entityType || $invoice->getEntityId() !== $entityId) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'صورتحساب یافت نشد', 404);
        }

        return $this->success(['data' => $invoice->toArray()]);
    }

    #[Route('/api/v1/billing/invoices/{uuid}/finalize', methods: ['POST'])]
    public function finalize(string $uuid, #[CurrentUser] User $user): JsonResponse
    {
        [$entityType, $entityId] = $this->resolveEntity($user);
        $invoice = $this->invoiceRepo->findByUuid($uuid);
        if ($invoice === null || $invoice->getEntityType() !== $entityType || $invoice->getEntityId() !== $entityId) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'صورتحساب یافت نشد', 404);
        }

        $this->invoiceService->finalize($invoice);

        return $this->success(['data' => $invoice->toArray()]);
    }

    // ── Claims (مطالبات بیمه) ──────────────────────────────────────────────────

    #[Route('/api/v1/billing/claims', methods: ['POST'])]
    public function createClaim(Request $request, #[CurrentUser] User $user): JsonResponse
    {
        [$entityType, $entityId] = $this->resolveEntity($user);
        if ($entityId === null) {
            return $this->error(ErrorCodes::ERR_FORBIDDEN_001, 'پروفایل یافت نشد', 403);
        }

        $data        = json_decode($request->getContent(), true) ?? [];
        $invoiceUuid = trim($data['invoice_uuid'] ?? '');
        if ($invoiceUuid === '') {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'invoice_uuid الزامی است', 422);
        }

        $invoice = $this->invoiceRepo->findByUuid($invoiceUuid);
        if ($invoice === null || $invoice->getEntityType() !== $entityType || $invoice->getEntityId() !== $entityId) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'صورتحساب یافت نشد', 404);
        }

        $claims = $this->claimService->createFromInvoice($invoice);

        return $this->success(['data' => array_map(fn(Claim $c) => $c->toArray(), $claims)], 201);
    }

    #[Route('/api/v1/billing/claims', methods: ['GET'])]
    public function listClaims(Request $request, #[CurrentUser] User $user): JsonResponse
    {
        [$entityType, $entityId] = $this->resolveEntity($user);
        if ($entityId === null) {
            return $this->error(ErrorCodes::ERR_FORBIDDEN_001, 'پروفایل یافت نشد', 403);
        }

        $status = $request->query->get('status') ?: null;
        $claims = $this->claimRepo->findByTenant($entityType, $entityId, $status);

        return $this->success(['data' => array_map(fn(Claim $c) => $c->toArray(), $claims)]);
    }

    #[Route('/api/v1/billing/claims/{uuid}/{action}', methods: ['POST'], requirements: ['action' => 'submit|approve|reject|pay'])]
    public function transitionClaim(string $uuid, string $action, Request $request, #[CurrentUser] User $user): JsonResponse
    {
        [$entityType, $entityId] = $this->resolveEntity($user);
        $claim = $this->claimRepo->findByUuid($uuid);
        if ($claim === null || $claim->getEntityType() !== $entityType || $claim->getEntityId() !== $entityId) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'مطالبه یافت نشد', 404);
        }

        $data   = json_decode($request->getContent(), true) ?? [];
        $target = match ($action) {
            'submit'  => Claim::STATUS_SUBMITTED,
            'approve' => Claim::STATUS_APPROVED,
            'reject'  => Claim::STATUS_REJECTED,
            'pay'     => Claim::STATUS_PAID,
        };

        if ($action === 'reject' && trim($data['reason'] ?? '') === '') {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'دلیل رد الزامی است', 422);
        }

        $this->claimService->transition($claim, $target, [
            'approved_rials' => isset($data['approved_rials']) ? (int) $data['approved_rials'] : null,
            'paid_rials'     => isset($data['paid_rials']) ? (int) $data['paid_rials'] : null,
            'reason'         => trim($data['reason'] ?? ''),
        ]);

        return $this->success(['data' => $claim->toArray()]);
    }

    #[Route('/api/v1/billing/reports/insurance-debt', methods: ['GET'])]
    public function insuranceDebt(#[CurrentUser] User $user): JsonResponse
    {
        [$entityType, $entityId] = $this->resolveEntity($user);
        if ($entityId === null) {
            return $this->error(ErrorCodes::ERR_FORBIDDEN_001, 'پروفایل یافت نشد', 403);
        }

        return $this->success(['data' => $this->claimRepo->debtReport($entityType, $entityId)]);
    }

    private function ownsSession($session, string $entityType, int $entityId): bool
    {
        $record = $session->getRecord();
        return $record->getEntityType() === $entityType && $record->getEntityId() === $entityId;
    }

    private function resolveEntity(User $user): array
    {
        if ($user->hasRole('ROLE_DOCTOR')) {
            $doctor = $this->doctorRepo->findByUser($user);
            return $doctor !== null ? ['doctor', $doctor->getId()] : ['doctor', null];
        }
        if ($user->hasRole('ROLE_CLINIC')) {
            $clinic = $this->clinicRepo->findByUser($user);
            return $clinic !== null ? ['clinic', $clinic->getId()] : ['clinic', null];
        }
        return ['unknown', null];
    }
}
