<?php

namespace App\Discount\Controller;

use App\Auth\Entity\User;
use App\Clinic\Repository\ClinicRepository;
use App\Discount\Entity\DiscountRule;
use App\Discount\Repository\DiscountRuleRepository;
use App\Discount\Service\DiscountEngine;
use App\Doctor\Repository\DoctorRepository;
use App\Patient\Repository\PatientSessionRepository;
use App\Secretary\Security\SecretaryAccessChecker;
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;

class DiscountController extends BaseController
{
    public function __construct(
        private readonly DiscountRuleRepository    $ruleRepo,
        private readonly DiscountEngine            $engine,
        private readonly DoctorRepository          $doctorRepo,
        private readonly ClinicRepository          $clinicRepo,
        private readonly PatientSessionRepository  $sessionRepo,
        private readonly SecretaryAccessChecker    $secretaryAccess,
        private readonly \App\Clinic\Security\ClinicDoctorAccessChecker $clinicDoctorAccess,
    ) {}

    /** @return array{0: string, 1: ?int} */
    private function resolveOwner(User $user): array
    {
        if ($user->hasRole('ROLE_DOCTOR')) {
            $memberClinicId = $this->clinicDoctorAccess->memberClinicId($user);
            if ($memberClinicId !== null) {
                return ['clinic', $memberClinicId];
            }
            return ['doctor', $this->doctorRepo->findByUser($user)?->getId()];
        }
        if ($user->hasRole('ROLE_CLINIC')) {
            return ['clinic', $this->clinicRepo->findByUser($user)?->getId()];
        }
        // منشی روی tenantِ محیطِ فعال؛ مجوز جدا با denyUnlessGranted.
        if ($user->hasRole('ROLE_SECRETARY')) {
            return $this->secretaryAccess->resolveOwnerEntity($user);
        }
        return ['unknown', null];
    }

    // ── Admin CRUD ────────────────────────────────────────────────────────────

    #[Route('/api/v1/admin/discount-rules', methods: ['GET'])]
    #[IsGranted('IS_AUTHENTICATED_FULLY')]
    public function list(#[CurrentUser] User $user): JsonResponse
    {
        $this->secretaryAccess->denyUnlessGranted($user, 'discounts', 'view');
        $this->clinicDoctorAccess->denyUnlessGranted($user, 'discounts', 'view');
        [$ownerType, $ownerId] = $this->resolveOwner($user);
        if ($ownerId === null) {
            return $this->error(ErrorCodes::ERR_AUTH_006, 'دسترسی ممنوع', 403);
        }
        $items = array_map(fn(DiscountRule $r) => $r->toArray(), $this->ruleRepo->findAllForOwner($ownerType, $ownerId));
        return $this->success(['data' => $items]);
    }

    #[Route('/api/v1/admin/discount-rules', methods: ['POST'])]
    #[IsGranted('IS_AUTHENTICATED_FULLY')]
    public function create(Request $request, #[CurrentUser] User $user): JsonResponse
    {
        $this->secretaryAccess->denyUnlessGranted($user, 'discounts', 'create');
        $this->clinicDoctorAccess->denyUnlessGranted($user, 'discounts', 'create');
        [$ownerType, $ownerId] = $this->resolveOwner($user);
        if ($ownerId === null) {
            return $this->error(ErrorCodes::ERR_AUTH_006, 'دسترسی ممنوع', 403);
        }

        $data = json_decode($request->getContent(), true) ?? [];
        $name = trim((string) ($data['name'] ?? ''));
        $type = (string) ($data['type'] ?? '');

        if ($name === '') {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'نام قانون الزامی است', 422, 'name');
        }
        if (!in_array($type, DiscountRule::TYPES, true)) {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'نوع قانون نامعتبر است', 422, 'type');
        }

        $rule = new DiscountRule($ownerType, $ownerId, $name, $type);
        $this->applyPayload($rule, $data);
        $this->ruleRepo->save($rule);

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

    #[Route('/api/v1/admin/discount-rules/{uuid}', methods: ['PATCH'])]
    #[IsGranted('IS_AUTHENTICATED_FULLY')]
    public function update(string $uuid, Request $request, #[CurrentUser] User $user): JsonResponse
    {
        $this->secretaryAccess->denyUnlessGranted($user, 'discounts', 'update');
        $this->clinicDoctorAccess->denyUnlessGranted($user, 'discounts', 'update');
        [$ownerType, $ownerId] = $this->resolveOwner($user);
        if ($ownerId === null) {
            return $this->error(ErrorCodes::ERR_AUTH_006, 'دسترسی ممنوع', 403);
        }
        $rule = $this->ruleRepo->findByUuidForOwner($uuid, $ownerType, $ownerId);
        if ($rule === null) {
            return $this->error(ErrorCodes::ERR_VALIDATION_002, 'قانون یافت نشد', 404);
        }

        $data = json_decode($request->getContent(), true) ?? [];
        if (array_key_exists('name', $data)) {
            $name = trim((string) $data['name']);
            if ($name === '') {
                return $this->error(ErrorCodes::ERR_VALIDATION_001, 'نام قانون الزامی است', 422, 'name');
            }
            $rule->setName($name);
        }
        if (array_key_exists('type', $data)) {
            if (!in_array((string) $data['type'], DiscountRule::TYPES, true)) {
                return $this->error(ErrorCodes::ERR_VALIDATION_001, 'نوع قانون نامعتبر است', 422, 'type');
            }
            $rule->setType((string) $data['type']);
        }
        $this->applyPayload($rule, $data);
        $this->ruleRepo->save($rule);

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

    #[Route('/api/v1/admin/discount-rules/{uuid}', methods: ['DELETE'])]
    #[IsGranted('IS_AUTHENTICATED_FULLY')]
    public function delete(string $uuid, #[CurrentUser] User $user): JsonResponse
    {
        $this->secretaryAccess->denyUnlessGranted($user, 'discounts', 'delete');
        $this->clinicDoctorAccess->denyUnlessGranted($user, 'discounts', 'delete');
        [$ownerType, $ownerId] = $this->resolveOwner($user);
        if ($ownerId === null) {
            return $this->error(ErrorCodes::ERR_AUTH_006, 'دسترسی ممنوع', 403);
        }
        $rule = $this->ruleRepo->findByUuidForOwner($uuid, $ownerType, $ownerId);
        if ($rule === null) {
            return $this->error(ErrorCodes::ERR_VALIDATION_002, 'قانون یافت نشد', 404);
        }
        $this->ruleRepo->remove($rule);
        return $this->success(['data' => ['deleted' => true]]);
    }

    // ── Suggestions for a session ─────────────────────────────────────────────

    #[Route('/api/v1/session/{uuid}/discount-suggestions', methods: ['GET'])]
    #[IsGranted('IS_AUTHENTICATED_FULLY')]
    public function suggestions(string $uuid, #[CurrentUser] User $user): JsonResponse
    {
        [$ownerType, $ownerId] = $this->resolveOwner($user);
        if ($ownerId === null) {
            return $this->error(ErrorCodes::ERR_AUTH_006, 'دسترسی ممنوع', 403);
        }
        $session = $this->sessionRepo->findByUuid($uuid);
        if ($session === null) {
            return $this->error(ErrorCodes::ERR_VALIDATION_002, 'پرونده یافت نشد', 404);
        }
        $record = $session->getRecord();
        if ($record->getEntityType() !== $ownerType || $record->getEntityId() !== $ownerId) {
            return $this->error(ErrorCodes::ERR_AUTH_006, 'دسترسی ممنوع', 403);
        }
        return $this->success(['data' => $this->engine->evaluate($session)]);
    }

    private function applyPayload(DiscountRule $rule, array $data): void
    {
        if (array_key_exists('discount_type', $data)) {
            $dt = (string) $data['discount_type'];
            $rule->setDiscountType($dt === DiscountRule::DISCOUNT_FIXED ? DiscountRule::DISCOUNT_FIXED : DiscountRule::DISCOUNT_PERCENT);
        }
        if (array_key_exists('value', $data))          { $rule->setValue((int) $data['value']); }
        if (array_key_exists('priority', $data))       { $rule->setPriority((int) $data['priority']); }
        if (array_key_exists('combinable', $data))     { $rule->setCombinable((bool) $data['combinable']); }
        if (array_key_exists('active', $data))         { $rule->setActive((bool) $data['active']); }
        if (array_key_exists('valid_from', $data))     { $rule->setValidFrom($data['valid_from'] !== null ? (int) $data['valid_from'] : null); }
        if (array_key_exists('valid_to', $data))       { $rule->setValidTo($data['valid_to'] !== null ? (int) $data['valid_to'] : null); }
        if (array_key_exists('target_tag_uuid', $data))  { $rule->setTargetTagUuid($data['target_tag_uuid'] !== null ? (string) $data['target_tag_uuid'] : null); }
        if (array_key_exists('target_record_uuid', $data)) { $rule->setTargetRecordUuid($data['target_record_uuid'] !== null ? (string) $data['target_record_uuid'] : null); }
        if (array_key_exists('target_service_item_uuid', $data)) { $rule->setTargetServiceItemUuid($data['target_service_item_uuid'] !== null ? (string) $data['target_service_item_uuid'] : null); }
        if (array_key_exists('min_amount_rials', $data)) { $rule->setMinAmountRials($data['min_amount_rials'] !== null ? (int) $data['min_amount_rials'] : null); }
        if (array_key_exists('min_visit_count', $data))  { $rule->setMinVisitCount($data['min_visit_count'] !== null ? (int) $data['min_visit_count'] : null); }
        if (array_key_exists('occasion_kind', $data))    { $rule->setOccasionKind($data['occasion_kind'] !== null ? (string) $data['occasion_kind'] : null); }
    }
}
