<?php

namespace App\Policy\Controller;

use App\Auth\Entity\User;
use App\Branch\Service\BranchResolver;
use App\Policy\Entity\Policy;
use App\Policy\Entity\PolicySimulationRun;
use App\Policy\Repository\PolicyRepository;
use App\Policy\Repository\PolicySimulationRunRepository;
use App\Policy\Simulation\PolicySimulator;
use App\Policy\Simulation\SimulationSampler;
use App\Policy\Template\PolicyTemplateRegistry;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Controller\BaseController;
use App\Shared\Exception\AppException;
use App\Shared\Tenant\TenantOwnershipChecker;
use OpenApi\Attributes as OA;
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;

#[OA\Tag(name: 'Policy')]
#[IsGranted('IS_AUTHENTICATED_FULLY')]
class PolicySimulationController extends BaseController
{
    public function __construct(
        private readonly PolicyRepository              $policies,
        private readonly PolicySimulationRunRepository $runs,
        private readonly PolicySimulator               $simulator,
        private readonly PolicyTemplateRegistry        $templates,
        private readonly BranchResolver                $branches,
        private readonly TenantOwnershipChecker        $ownership,
    ) {}

    /** الگوهای آمادهٔ قانون — ورودیِ فرم ساخت. */
    #[Route('/api/v1/policy-templates', name: 'policy_templates', methods: ['GET'])]
    public function templates(): JsonResponse
    {
        return $this->success($this->templates->describe());
    }

    /**
     * اجرای آزمایشی روی نوبت‌های واقعی گذشته. هیچ چیزی جز خودِ نتیجه ثبت نمی‌شود.
     */
    #[Route('/api/v1/policy/{uuid}/simulate', name: 'policy_simulate', methods: ['POST'])]
    public function simulate(#[CurrentUser] User $user, string $uuid, Request $request): JsonResponse
    {
        $policy = $this->requirePolicy($user, $uuid);
        $data   = json_decode($request->getContent(), true);

        $size = is_array($data) && is_numeric($data['sample_size'] ?? null)
            ? (int) $data['sample_size']
            : SimulationSampler::DEFAULT_SIZE;

        // سقف صریح است نه بی‌صدا: کاربری که ۵۰۰ خواسته باید بداند ۵۰ گرفته.
        if ($size < 1 || $size > SimulationSampler::MAX_SIZE) {
            return $this->error(
                ErrorCodes::ERR_VALIDATION_001,
                sprintf('اندازهٔ نمونه باید بین ۱ و %d باشد', SimulationSampler::MAX_SIZE),
                422,
                'sample_size',
            );
        }

        $run = $this->simulator->simulate($policy, $size, $user);

        return $this->success($run->toArray(), 201);
    }

    /** تاریخچهٔ اجراهای آزمایشی یک قانون. */
    #[Route('/api/v1/policy/{uuid}/simulations', name: 'policy_simulations', methods: ['GET'])]
    public function history(#[CurrentUser] User $user, string $uuid): JsonResponse
    {
        $policy = $this->requirePolicy($user, $uuid);

        return $this->success(array_map(
            static fn (PolicySimulationRun $r): array => $r->toArray(),
            $this->runs->historyFor($policy),
        ));
    }

    private function requirePolicy(User $user, string $uuid): Policy
    {
        $policy = $this->policies->findByUuid($uuid);
        [$entityType, $entityId] = $this->branches->pair($user);

        if ($policy === null || !$this->ownership->belongsToPair($entityType, $entityId, $policy)) {
            throw new AppException(ErrorCodes::ERR_NOT_FOUND_001, 'قانون یافت نشد', 404);
        }

        return $policy;
    }
}
