<?php

namespace App\Resource\Controller;

use App\Appointment\Availability\Repository\ResourceOccupancyRepository;
use App\Auth\Entity\User;
use App\Resource\Entity\ClinicResource;
use App\Resource\Repository\ClinicResourceRepository;
use App\Resource\Service\ResourceContext;
use App\Resource\Service\ResourceService;
use App\Resource\Service\SkillAssignmentService;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Controller\BaseController;
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: 'Resource')]
#[IsGranted('IS_AUTHENTICATED_FULLY')]
class ResourceController extends BaseController
{
    use ResourcePermissionTrait;

    public function __construct(
        private readonly ResourceContext          $context,
        private readonly ClinicResourceRepository $resources,
        private readonly ResourceService          $service,
        private readonly SkillAssignmentService   $skills,
        private readonly ResourceOccupancyRepository $occupancy,
    ) {}

    #[Route('/api/v1/resources', name: 'resource_list', methods: ['GET'])]
    public function list(#[CurrentUser] User $user, Request $request): JsonResponse
    {
        $this->denyUnlessGranted($user, 'view');

        [$entityType, $entityId] = $this->context->pair($user);

        $addressUuid = $request->query->get('address_uuid');
        $typeUuid    = $request->query->get('type_uuid');
        $activeParam = $request->query->get('active');

        $filters = [
            'address'   => is_string($addressUuid) && $addressUuid !== '' ? $this->context->address($user, $addressUuid) : null,
            'type'      => is_string($typeUuid) && $typeUuid !== '' ? $this->context->type($user, $typeUuid) : null,
            'active'    => $activeParam === null || $activeParam === '' ? null : filter_var($activeParam, FILTER_VALIDATE_BOOL),
            'skillUuid' => $request->query->get('skill_uuid') ?: null,
        ];

        // مهارتِ محیط دیگر نباید بی‌صدا «هیچ نتیجه» بدهد؛ ۴۰۴ صریح است.
        if ($filters['skillUuid'] !== null) {
            $this->context->skill($user, $filters['skillUuid']);
        }

        return $this->success(array_map(
            static fn (ClinicResource $r): array => $r->toArray(),
            $this->resources->findForPair($entityType, $entityId, $filters),
        ));
    }

    #[Route('/api/v1/resource', name: 'resource_create', methods: ['POST'])]
    public function create(#[CurrentUser] User $user, Request $request): JsonResponse
    {
        $this->denyUnlessGranted($user, 'update');

        $data = json_decode($request->getContent(), true);

        if (!is_array($data) || !is_string($data['address_uuid'] ?? null)) {
            return $this->error(ErrorCodes::ERR_VALIDATION_002, 'فیلد address_uuid الزامی است', 422, 'address_uuid');
        }

        if (!is_string($data['type_uuid'] ?? null)) {
            return $this->error(ErrorCodes::ERR_VALIDATION_002, 'فیلد type_uuid الزامی است', 422, 'type_uuid');
        }

        $address = $this->context->address($user, $data['address_uuid']);
        $type    = $this->context->type($user, $data['type_uuid']);

        return $this->success($this->service->create($address, $type, $data)->toArray(), 201);
    }

    #[Route('/api/v1/resource/{uuid}', name: 'resource_show', methods: ['GET'])]
    public function show(#[CurrentUser] User $user, string $uuid): JsonResponse
    {
        $this->denyUnlessGranted($user, 'view');

        $resource = $this->context->resource($user, $uuid);

        // شمار نوبت‌های آینده کنار خودِ منبع می‌آید تا پنل بتواند پیش از خاموش‌کردنش
        // هشدار بدهد. در فهرست نمی‌آید — آنجا یک کوئری per ردیف می‌شد.
        return $this->success($resource->toArray() + [
            'upcoming_appointments' => $this->occupancy->countUpcomingAppointments((int) $resource->getId()),
        ]);
    }

    #[Route('/api/v1/resource/{uuid}', name: 'resource_update', methods: ['PATCH'])]
    public function update(#[CurrentUser] User $user, string $uuid, Request $request): JsonResponse
    {
        $this->denyUnlessGranted($user, 'update');

        $data = json_decode($request->getContent(), true);

        if (!is_array($data)) {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'بدنهٔ درخواست نامعتبر است', 422);
        }

        $resource = $this->context->resource($user, $uuid);

        if (is_string($data['type_uuid'] ?? null)) {
            $resource->setType($this->context->type($user, $data['type_uuid']));
        }

        return $this->success($this->service->update($resource, $data)->toArray());
    }

    #[Route('/api/v1/resource/{uuid}', name: 'resource_delete', methods: ['DELETE'])]
    public function delete(#[CurrentUser] User $user, string $uuid): JsonResponse
    {
        $this->denyUnlessGranted($user, 'update');

        $this->service->delete($this->context->resource($user, $uuid));

        return $this->success(null);
    }

    /** جایگزینی کامل مهارت‌های منبع: مهارتی که در بدنه نیست، برداشته می‌شود. */
    #[Route('/api/v1/resource/{uuid}/skills', name: 'resource_skills_replace', methods: ['PUT'])]
    public function replaceSkills(#[CurrentUser] User $user, string $uuid, Request $request): JsonResponse
    {
        $this->denyUnlessGranted($user, 'update');

        $data = json_decode($request->getContent(), true);

        if (!is_array($data) || !is_array($data['skills'] ?? null)) {
            return $this->error(ErrorCodes::ERR_VALIDATION_002, 'فیلد skills الزامی است', 422, 'skills');
        }

        $resource = $this->context->resource($user, $uuid);
        $this->skills->replace($user, $resource, $data['skills']);

        return $this->success($resource->toArray());
    }
}
