<?php

namespace App\Settlement\Controller;

use App\Auth\Entity\User;
use App\Settlement\Entity\Settlement;
use App\Settlement\Entity\WalletTransaction;
use App\Settlement\Repository\SettlementRepository;
use App\Settlement\Repository\WalletTransactionRepository;
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: 'Settlements')]
#[IsGranted('IS_AUTHENTICATED_FULLY')]
class SettlementController extends BaseController
{
    public function __construct(
        private readonly SettlementRepository       $settlementRepo,
        private readonly WalletTransactionRepository $walletRepo,
    ) {}

    // ── Wallet ────────────────────────────────────────────────────────────────

    #[OA\Get(
        path: '/api/v1/wallet/balance',
        summary: 'Get current wallet balance and recent transactions',
        security: [['bearerAuth' => []]],
        responses: [
            new OA\Response(
                response: 200,
                description: 'Wallet balance and recent transactions',
                content: new OA\JsonContent(
                    properties: [
                        new OA\Property(property: 'success', type: 'boolean', example: true),
                        new OA\Property(property: 'data', properties: [
                            new OA\Property(property: 'balance_rials', type: 'integer'),
                            new OA\Property(property: 'recent_transactions', type: 'array', items: new OA\Items(type: 'object')),
                        ], type: 'object'),
                    ]
                )
            ),
            new OA\Response(response: 401, description: 'Unauthorized'),
        ]
    )]
    #[Route('/api/v1/wallet/balance', methods: ['GET'])]
    public function balance(#[CurrentUser] User $user): JsonResponse
    {
        $balance      = $this->settlementRepo->getWalletBalance($user);
        $transactions = array_map(
            fn(WalletTransaction $t) => $t->toArray(),
            $this->walletRepo->findByUser($user, 10)
        );

        return $this->success([
            'balance_rials'        => $balance,
            'recent_transactions'  => $transactions,
        ]);
    }

    #[OA\Get(
        path: '/api/v1/wallet/transactions',
        summary: 'List all wallet transactions for the authenticated user',
        security: [['bearerAuth' => []]],
        responses: [
            new OA\Response(
                response: 200,
                description: 'List of wallet transactions',
                content: new OA\JsonContent(
                    properties: [
                        new OA\Property(property: 'success', type: 'boolean', example: true),
                        new OA\Property(property: 'data', type: 'array', items: new OA\Items(type: 'object')),
                    ]
                )
            ),
            new OA\Response(response: 401, description: 'Unauthorized'),
        ]
    )]
    #[Route('/api/v1/wallet/transactions', methods: ['GET'])]
    public function transactions(#[CurrentUser] User $user): JsonResponse
    {
        $transactions = array_map(
            fn(WalletTransaction $t) => $t->toArray(),
            $this->walletRepo->findByUser($user)
        );

        return $this->success(['data' => $transactions]);
    }

    // ── Settlement Requests ───────────────────────────────────────────────────

    #[OA\Post(
        path: '/api/v1/settlement',
        summary: 'Request a new settlement (withdrawal)',
        security: [['bearerAuth' => []]],
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(
                required: ['amount_rials'],
                properties: [
                    new OA\Property(property: 'amount_rials', type: 'integer', minimum: 1),
                    new OA\Property(property: 'bank_account', type: 'object', nullable: true),
                ]
            )
        ),
        responses: [
            new OA\Response(
                response: 201,
                description: 'Settlement request created',
                content: new OA\JsonContent(
                    properties: [
                        new OA\Property(property: 'success', type: 'boolean', example: true),
                        new OA\Property(property: 'data', type: 'object'),
                    ]
                )
            ),
            new OA\Response(response: 401, description: 'Unauthorized'),
            new OA\Response(response: 422, description: 'Validation error or insufficient balance'),
        ]
    )]
    #[Route('/api/v1/settlement', methods: ['POST'])]
    public function request(Request $request, #[CurrentUser] User $user): JsonResponse
    {
        $data        = json_decode($request->getContent(), true) ?? [];
        $amountRials = (int) ($data['amount_rials'] ?? 0);
        $bankAccount = $data['bank_account'] ?? null;

        if ($amountRials <= 0) {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'مبلغ برداشت باید بیشتر از صفر باشد', 422);
        }

        $balance = $this->settlementRepo->getWalletBalance($user);
        if ($amountRials > $balance) {
            return $this->error(ErrorCodes::ERR_CONFLICT_001, 'موجودی کافی نیست', 422);
        }

        $settlement = new Settlement($user, $amountRials, $bankAccount);
        $this->settlementRepo->save($settlement);

        // Reserve amount by debit transaction
        $tx = new WalletTransaction($user, $amountRials, WalletTransaction::TYPE_DEBIT, $balance - $amountRials);
        $tx->setDescription('درخواست برداشت ' . $settlement->getUuid());
        $this->walletRepo->save($tx);

        return $this->success(['data' => $settlement->toArray()], 201);
    }

    #[OA\Get(
        path: '/api/v1/settlement',
        summary: 'List settlement requests for the authenticated user',
        security: [['bearerAuth' => []]],
        responses: [
            new OA\Response(
                response: 200,
                description: 'List of settlement requests',
                content: new OA\JsonContent(
                    properties: [
                        new OA\Property(property: 'success', type: 'boolean', example: true),
                        new OA\Property(property: 'data', type: 'array', items: new OA\Items(type: 'object')),
                    ]
                )
            ),
            new OA\Response(response: 401, description: 'Unauthorized'),
        ]
    )]
    #[Route('/api/v1/settlement', methods: ['GET'])]
    public function listMine(#[CurrentUser] User $user): JsonResponse
    {
        $settlements = array_map(
            fn(Settlement $s) => $s->toArray(),
            $this->settlementRepo->findByUser($user)
        );

        return $this->success(['data' => $settlements]);
    }

    #[OA\Get(
        path: '/api/v1/settlement/{uuid}',
        summary: 'Get a settlement request by UUID (own or admin)',
        security: [['bearerAuth' => []]],
        parameters: [
            new OA\Parameter(name: 'uuid', in: 'path', required: true, schema: new OA\Schema(type: 'string')),
        ],
        responses: [
            new OA\Response(
                response: 200,
                description: 'Settlement request details',
                content: new OA\JsonContent(
                    properties: [
                        new OA\Property(property: 'success', type: 'boolean', example: true),
                        new OA\Property(property: 'data', type: 'object'),
                    ]
                )
            ),
            new OA\Response(response: 401, description: 'Unauthorized'),
            new OA\Response(response: 403, description: 'Forbidden'),
            new OA\Response(response: 404, description: 'Not found'),
        ]
    )]
    #[Route('/api/v1/settlement/{uuid}', methods: ['GET'])]
    public function get(string $uuid, #[CurrentUser] User $user): JsonResponse
    {
        $settlement = $this->settlementRepo->findByUuid($uuid);
        if ($settlement === null) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'درخواست یافت نشد', 404);
        }

        if ($settlement->getUser()->getId() !== $user->getId() && !$user->hasRole('ROLE_ADMIN')) {
            return $this->error(ErrorCodes::ERR_AUTH_006, 'دسترسی ممنوع', 403);
        }

        return $this->success(['data' => $settlement->toArray()]);
    }

    // ── Admin Actions ─────────────────────────────────────────────────────────

    #[OA\Post(
        path: '/api/v1/settlement/{uuid}/approve',
        summary: 'Approve a pending settlement request (ROLE_ADMIN)',
        security: [['bearerAuth' => []]],
        requestBody: new OA\RequestBody(
            required: false,
            content: new OA\JsonContent(
                properties: [
                    new OA\Property(property: 'note', type: 'string', nullable: true),
                ]
            )
        ),
        parameters: [
            new OA\Parameter(name: 'uuid', in: 'path', required: true, schema: new OA\Schema(type: 'string')),
        ],
        responses: [
            new OA\Response(
                response: 200,
                description: 'Settlement approved',
                content: new OA\JsonContent(
                    properties: [
                        new OA\Property(property: 'success', type: 'boolean', example: true),
                        new OA\Property(property: 'data', type: 'object'),
                    ]
                )
            ),
            new OA\Response(response: 401, description: 'Unauthorized'),
            new OA\Response(response: 403, description: 'Forbidden – ROLE_ADMIN required'),
            new OA\Response(response: 404, description: 'Not found'),
            new OA\Response(response: 422, description: 'Settlement is not in pending state'),
        ]
    )]
    #[IsGranted('ROLE_ADMIN')]
    #[Route('/api/v1/settlement/{uuid}/approve', methods: ['POST'])]
    public function approve(string $uuid, Request $request, #[CurrentUser] User $admin): JsonResponse
    {
        $settlement = $this->settlementRepo->findByUuid($uuid);
        if ($settlement === null) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'درخواست یافت نشد', 404);
        }

        if ($settlement->getStatus() !== Settlement::STATUS_PENDING) {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'این درخواست قابل تأیید نیست', 422);
        }

        $data = json_decode($request->getContent(), true) ?? [];
        $settlement->approve($admin->getId(), $data['note'] ?? null);
        $this->settlementRepo->save($settlement);

        return $this->success(['data' => $settlement->toArray()]);
    }

    #[OA\Post(
        path: '/api/v1/settlement/{uuid}/reject',
        summary: 'Reject a pending settlement request (ROLE_ADMIN)',
        security: [['bearerAuth' => []]],
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(
                required: ['note'],
                properties: [
                    new OA\Property(property: 'note', type: 'string', description: 'Rejection reason (required)'),
                ]
            )
        ),
        parameters: [
            new OA\Parameter(name: 'uuid', in: 'path', required: true, schema: new OA\Schema(type: 'string')),
        ],
        responses: [
            new OA\Response(
                response: 200,
                description: 'Settlement rejected and amount refunded to wallet',
                content: new OA\JsonContent(
                    properties: [
                        new OA\Property(property: 'success', type: 'boolean', example: true),
                        new OA\Property(property: 'data', type: 'object'),
                    ]
                )
            ),
            new OA\Response(response: 401, description: 'Unauthorized'),
            new OA\Response(response: 403, description: 'Forbidden – ROLE_ADMIN required'),
            new OA\Response(response: 404, description: 'Not found'),
            new OA\Response(response: 422, description: 'Settlement is not pending or note is missing'),
        ]
    )]
    #[IsGranted('ROLE_ADMIN')]
    #[Route('/api/v1/settlement/{uuid}/reject', methods: ['POST'])]
    public function reject(string $uuid, Request $request, #[CurrentUser] User $admin): JsonResponse
    {
        $settlement = $this->settlementRepo->findByUuid($uuid);
        if ($settlement === null) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'درخواست یافت نشد', 404);
        }

        if ($settlement->getStatus() !== Settlement::STATUS_PENDING) {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'این درخواست قابل رد نیست', 422);
        }

        $data = json_decode($request->getContent(), true) ?? [];
        $note = trim($data['note'] ?? '');
        if (empty($note)) {
            return $this->error(ErrorCodes::ERR_VALIDATION_002, 'دلیل رد الزامی است', 422);
        }

        $settlement->reject($admin->getId(), $note);
        $this->settlementRepo->save($settlement);

        // Refund the reserved amount back to wallet
        $balance = $this->settlementRepo->getWalletBalance($settlement->getUser());
        $tx      = new WalletTransaction(
            $settlement->getUser(),
            $settlement->getAmountRials(),
            WalletTransaction::TYPE_CREDIT,
            $balance + $settlement->getAmountRials()
        );
        $tx->setDescription('برگشت برداشت رد شده ' . $settlement->getUuid());
        $this->walletRepo->save($tx);

        return $this->success(['data' => $settlement->toArray()]);
    }
}
