<?php

namespace App\Branch\Controller;

use App\Auth\Entity\User;
use App\Branch\Entity\Room;
use App\Branch\Repository\RoomRepository;
use App\Branch\Service\BranchResolver;
use App\Branch\Service\RoomService;
use App\Clinic\Security\ClinicDoctorAccessChecker;
use App\Secretary\Security\SecretaryAccessChecker;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Controller\BaseController;
use App\Shared\Context\EntityContext;
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: 'Branch')]
#[IsGranted('IS_AUTHENTICATED_FULLY')]
class RoomController extends BaseController
{
    public function __construct(
        private readonly BranchResolver            $branches,
        private readonly RoomRepository            $rooms,
        private readonly RoomService               $roomService,
        private readonly TenantOwnershipChecker    $ownership,
        private readonly SecretaryAccessChecker    $secretaryAccess,
        private readonly ClinicDoctorAccessChecker $clinicDoctorAccess,
    ) {}

    /** @param 'view'|'update' $action */
    private function denyUnlessGranted(User $user, string $action): void
    {
        $this->secretaryAccess->denyUnlessGranted($user, 'appointment_settings', $action);
        $this->clinicDoctorAccess->denyUnlessGranted($user, 'appointment_settings', $action);
    }

    /**
     * مالکیت صریح سنجیده می‌شود و به TenantFilter تکیه نمی‌کنیم: جداسازی سختِ فیلتر
     * فقط روی محیطِ «انتخاب‌شده» اعمال می‌شود (‏{@see EntityContext::$chosen}) و پزشکی
     * که هنوز محیطی برنگزیده، اتاق کلینیک دیگر را می‌دید — با تست
     * RoomCrudTest::testForeignRoomIsNotFound گرفته شد.
     *
     * ۴۰۴ نه ۴۰۳، همان رفتار فیلتر: وجود دادهٔ محیط بیگانه لو نمی‌رود.
     */
    private function requireRoom(User $user, string $uuid): Room
    {
        $room = $this->rooms->findByUuid($uuid);
        [$entityType, $entityId] = $this->branches->pair($user);

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

        return $room;
    }

    #[Route('/api/v1/branch/{addressUuid}/rooms', name: 'branch_rooms_list', methods: ['GET'])]
    public function list(#[CurrentUser] User $user, string $addressUuid): JsonResponse
    {
        $this->denyUnlessGranted($user, 'view');

        $address = $this->branches->resolve($user, $addressUuid);

        return $this->success(array_map(
            static fn (Room $room): array => $room->toArray(),
            $this->rooms->findForAddress($address),
        ));
    }

    #[Route('/api/v1/room', name: 'room_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');
        }

        // جفت محیط اتاق از همین آدرس مشتق می‌شود، نه از بدنهٔ درخواست.
        $address = $this->branches->resolve($user, $data['address_uuid']);
        $room    = $this->roomService->create($address, $data);

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

    #[Route('/api/v1/room/{uuid}', name: 'room_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);
        }

        $room = $this->roomService->update($this->requireRoom($user, $uuid), $data);

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

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

        $this->roomService->delete($this->requireRoom($user, $uuid));

        return $this->success(null);
    }
}
