<?php

namespace App\Staff\Controller;

use App\Auth\Entity\User;
use App\Clinic\Repository\ClinicRepository;
use App\Doctor\Repository\DoctorRepository;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Controller\BaseController;
use App\Staff\Entity\ClinicStaff;
use App\Staff\Repository\ClinicStaffRepository;
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: 'Staff')]
#[IsGranted('IS_AUTHENTICATED_FULLY')]
class StaffController extends BaseController
{
    public function __construct(
        private readonly ClinicStaffRepository $staffRepo,
        private readonly DoctorRepository      $doctorRepo,
        private readonly ClinicRepository      $clinicRepo,
    ) {}

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

        $staff = array_map(
            fn(ClinicStaff $s) => $s->toArray(),
            $this->staffRepo->findByEntity($entityType, $entityId)
        );

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

    #[Route('/api/v1/staff', 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) ?? [];
        $fullName = trim($data['full_name'] ?? '');

        if ($fullName === '') {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'full_name الزامی است', 422);
        }

        $staff = new ClinicStaff($entityType, $entityId, $fullName);
        $staff->setPhone($data['phone'] ?? null);
        $staff->setJobTitle($data['job_title'] ?? null);
        $staff->setAddress($data['address'] ?? null);
        $staff->setNationalCode($this->toLatinDigits($data['national_code'] ?? null));

        $this->staffRepo->save($staff);

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

    #[Route('/api/v1/staff/{uuid}', methods: ['PATCH'])]
    public function update(string $uuid, Request $request, #[CurrentUser] User $user): JsonResponse
    {
        $staff = $this->staffRepo->findByUuid($uuid);
        if ($staff === null) {
            return $this->error(ErrorCodes::ERR_STAFF_NOT_FOUND, ErrorCodes::message(ErrorCodes::ERR_STAFF_NOT_FOUND), 404);
        }

        if (!$this->ownsStaff($staff, $user)) {
            return $this->error(ErrorCodes::ERR_FORBIDDEN_001, ErrorCodes::message(ErrorCodes::ERR_FORBIDDEN_001), 403);
        }

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

        if (isset($data['full_name']) && trim($data['full_name']) !== '') {
            $staff->setFullName(trim($data['full_name']));
        }
        if (array_key_exists('phone', $data))        { $staff->setPhone($data['phone']); }
        if (array_key_exists('job_title', $data))    { $staff->setJobTitle($data['job_title']); }
        if (array_key_exists('address', $data))      { $staff->setAddress($data['address']); }
        if (array_key_exists('national_code', $data)){ $staff->setNationalCode($this->toLatinDigits($data['national_code'])); }

        $this->staffRepo->save($staff);

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

    #[Route('/api/v1/staff/{uuid}/toggle', methods: ['PATCH'])]
    public function toggle(string $uuid, #[CurrentUser] User $user): JsonResponse
    {
        $staff = $this->staffRepo->findByUuid($uuid);
        if ($staff === null) {
            return $this->error(ErrorCodes::ERR_STAFF_NOT_FOUND, ErrorCodes::message(ErrorCodes::ERR_STAFF_NOT_FOUND), 404);
        }

        if (!$this->ownsStaff($staff, $user)) {
            return $this->error(ErrorCodes::ERR_FORBIDDEN_001, ErrorCodes::message(ErrorCodes::ERR_FORBIDDEN_001), 403);
        }

        $staff->toggleActive();
        $this->staffRepo->save($staff);

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

    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];
    }

    private function ownsStaff(ClinicStaff $staff, User $user): bool
    {
        if ($user->hasRole('ROLE_ADMIN')) {
            return true;
        }

        [$entityType, $entityId] = $this->resolveEntity($user);
        return $entityId !== null
            && $staff->getEntityType() === $entityType
            && $staff->getEntityId() === $entityId;
    }

    private function toLatinDigits(?string $str): ?string
    {
        if ($str === null) {
            return null;
        }
        return strtr($str, [
            '۰' => '0', '۱' => '1', '۲' => '2', '۳' => '3', '۴' => '4',
            '۵' => '5', '۶' => '6', '۷' => '7', '۸' => '8', '۹' => '9',
            '٠' => '0', '١' => '1', '٢' => '2', '٣' => '3', '٤' => '4',
            '٥' => '5', '٦' => '6', '٧' => '7', '٨' => '8', '٩' => '9',
        ]);
    }
}
