<?php

namespace App\PaymentMethod\Controller;

use App\Auth\Entity\User;
use App\PaymentMethod\Service\PaymentMethodService;
use App\Secretary\Security\SecretaryAccessChecker;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Context\EntityContext;
use App\Shared\Context\EntityContextResolver;
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;
use OpenApi\Attributes as OA;

/**
 * Per-environment payment methods: bank accounts and POS (card reader) devices.
 *
 * اسکوپ محیط فعال است، نه کاربر: پزشکی که هم مطب شخصی دارد و هم کلینیک، بسته به
 * محیط فعالش کارت‌های متفاوتی می‌بیند. کارت‌های بازمانده‌ای که هنوز محیطی ندارند
 * با `entity_type: null` در همان فهرست می‌آیند و با endpoint انتساب به محیط فعال
 * چسبانده می‌شوند.
 */
#[OA\Tag(name: 'Payment Methods')]
#[Route('/api/v1/my/payment-methods')]
#[IsGranted('IS_AUTHENTICATED_FULLY')]
class PaymentMethodController extends BaseController
{
    private const ALLOWED_ROLES = ['ROLE_CLINIC', 'ROLE_DOCTOR', 'ROLE_SECRETARY', 'ROLE_ADMIN'];

    public function __construct(
        private readonly PaymentMethodService   $service,
        private readonly SecretaryAccessChecker $secretaryAccess,
        private readonly \App\Clinic\Security\ClinicDoctorAccessChecker $clinicDoctorAccess,
        private readonly EntityContextResolver  $contextResolver,
    ) {}

    /** نقش مجاز + مجوز منشی روی منبع payments (روش‌های پرداخت زیرمجموعهٔ مالی است). */
    private function guard(User $user, string $action): EntityContext
    {
        $this->assertRole($user);
        $this->secretaryAccess->denyUnlessGranted($user, 'payments', $action);
        $this->clinicDoctorAccess->denyUnlessGranted($user, 'payments', $action);

        return $this->contextResolver->resolve($user);
    }

    // ---- Bank accounts -----------------------------------------------------

    #[Route('/bank-accounts', methods: ['GET'])]
    public function listBankAccounts(#[CurrentUser] User $user): JsonResponse
    {
        $context = $this->guard($user, 'view');

        return $this->success($this->service->listBankAccounts($context, $user));
    }

    #[Route('/bank-accounts', methods: ['POST'])]
    public function createBankAccount(Request $request, #[CurrentUser] User $user): JsonResponse
    {
        $context = $this->guard($user, 'create');
        $data    = json_decode($request->getContent(), true) ?? [];

        return $this->success($this->service->createBankAccount($context, $user, $data), 201);
    }

    #[Route('/bank-accounts/{uuid}', methods: ['PUT'])]
    public function updateBankAccount(string $uuid, Request $request, #[CurrentUser] User $user): JsonResponse
    {
        $context = $this->guard($user, 'update');
        $data    = json_decode($request->getContent(), true) ?? [];

        return $this->success($this->service->updateBankAccount($context, $uuid, $data));
    }

    #[Route('/bank-accounts/{uuid}/status', methods: ['PATCH'])]
    public function toggleBankAccountStatus(string $uuid, #[CurrentUser] User $user): JsonResponse
    {
        $context = $this->guard($user, 'update');

        return $this->success($this->service->toggleBankAccountStatus($context, $uuid));
    }

    #[Route('/bank-accounts/{uuid}/environment', methods: ['PATCH'])]
    public function assignBankAccountEnvironment(string $uuid, #[CurrentUser] User $user): JsonResponse
    {
        $context = $this->guard($user, 'update');

        return $this->success($this->service->assignBankAccountEnvironment($context, $user, $uuid));
    }

    // ---- POS devices -------------------------------------------------------

    #[Route('/pos', methods: ['GET'])]
    public function listPos(#[CurrentUser] User $user): JsonResponse
    {
        $context = $this->guard($user, 'view');

        return $this->success($this->service->listPos($context, $user));
    }

    #[Route('/pos', methods: ['POST'])]
    public function createPos(Request $request, #[CurrentUser] User $user): JsonResponse
    {
        $context = $this->guard($user, 'create');
        $data    = json_decode($request->getContent(), true) ?? [];

        return $this->success($this->service->createPos($context, $user, $data), 201);
    }

    #[Route('/pos/{uuid}', methods: ['PUT'])]
    public function updatePos(string $uuid, Request $request, #[CurrentUser] User $user): JsonResponse
    {
        $context = $this->guard($user, 'update');
        $data    = json_decode($request->getContent(), true) ?? [];

        return $this->success($this->service->updatePos($context, $uuid, $data));
    }

    #[Route('/pos/{uuid}/status', methods: ['PATCH'])]
    public function togglePosStatus(string $uuid, #[CurrentUser] User $user): JsonResponse
    {
        $context = $this->guard($user, 'update');

        return $this->success($this->service->togglePosStatus($context, $uuid));
    }

    #[Route('/pos/{uuid}/environment', methods: ['PATCH'])]
    public function assignPosEnvironment(string $uuid, #[CurrentUser] User $user): JsonResponse
    {
        $context = $this->guard($user, 'update');

        return $this->success($this->service->assignPosEnvironment($context, $user, $uuid));
    }

    private function assertRole(User $user): void
    {
        if (!array_intersect(self::ALLOWED_ROLES, $user->getRoles())) {
            throw new \App\Shared\Exception\AppException(ErrorCodes::ERR_FORBIDDEN_001, 'دسترسی ندارید', 403);
        }
    }
}
