<?php

namespace App\Representation\Controller;

use App\Auth\Entity\User;
use App\Auth\Repository\UserRepository;
use App\Representation\Entity\Representation;
use App\Representation\Repository\RepresentationRepository;
use App\Representation\Service\JalaliDateService;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Controller\BaseController;
use App\Shared\Service\InputValidator;
use Doctrine\ORM\EntityManagerInterface;
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: 'Representations')]
#[IsGranted('IS_AUTHENTICATED_FULLY')]
class RepresentationController extends BaseController
{
    public function __construct(
        private readonly RepresentationRepository $representationRepo,
        private readonly UserRepository           $userRepo,
        private readonly EntityManagerInterface   $em,
        private readonly JalaliDateService        $jalali,
    ) {}

    // ── CRUD ──────────────────────────────────────────────────────────────────

    #[OA\Post(
        path: '/api/v1/representation',
        summary: 'Create a new representation (ROLE_ADMIN)',
        security: [['bearerAuth' => []]],
        requestBody: new OA\RequestBody(
            required: true,
            content: new OA\JsonContent(
                required: ['full_name', 'mobile_number'],
                properties: [
                    new OA\Property(property: 'full_name', type: 'string'),
                    new OA\Property(property: 'mobile_number', type: 'string'),
                    new OA\Property(property: 'city_id', type: 'integer', nullable: true),
                    new OA\Property(property: 'commission_percent', type: 'number', format: 'float', nullable: true),
                    new OA\Property(property: 'bank_account', type: 'object', nullable: true),
                ]
            )
        ),
        responses: [
            new OA\Response(
                response: 201,
                description: 'Representation 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: 409,
                description: 'Conflict – user is already a representation',
                content: new OA\JsonContent(
                    properties: [
                        new OA\Property(property: 'success', type: 'boolean', example: false),
                        new OA\Property(property: 'errors', type: 'array', items: new OA\Items(
                            properties: [
                                new OA\Property(property: 'code', type: 'string'),
                                new OA\Property(property: 'message', type: 'string'),
                            ]
                        )),
                    ]
                )
            ),
            new OA\Response(response: 401, description: 'Unauthorized'),
            new OA\Response(response: 403, description: 'Forbidden – ROLE_ADMIN required'),
            new OA\Response(response: 422, description: 'Validation error'),
        ]
    )]
    #[IsGranted('ROLE_ADMIN')]
    #[Route('/api/v1/representation', methods: ['POST'])]
    public function create(Request $request): JsonResponse
    {
        $data     = json_decode($request->getContent(), true) ?? [];
        $mobile   = InputValidator::toEnglishDigits(trim((string) ($data['mobile_number'] ?? '')));
        $fullName = trim((string) ($data['full_name'] ?? ''));

        if (empty($mobile) || empty($fullName)) {
            return $this->error(ErrorCodes::ERR_VALIDATION_002, 'mobile_number و full_name الزامی است', 422);
        }

        if (!InputValidator::isValidIranMobile($mobile)) {
            return $this->error(ErrorCodes::ERR_VALIDATION_001, 'شماره موبایل نامعتبر است', 422, 'mobile_number');
        }

        $user = $this->userRepo->findByMobile($mobile);
        if ($user === null) {
            $user = new User($mobile);
            $this->em->persist($user);
        }
        $user->addRole('ROLE_REPRESENTATION');
        $this->em->flush();

        if ($this->representationRepo->findByUser($user) !== null) {
            return $this->error(ErrorCodes::ERR_CONFLICT_001, 'این کاربر قبلاً نماینده است', 409);
        }

        $rep = new Representation($user, $fullName);
        if (isset($data['city_id']))             $rep->setCityId($data['city_id'] ? (int)$data['city_id'] : null);
        if (!empty($data['commission_percent'])) $rep->setCommissionPercent((string)$data['commission_percent']);
        if (!empty($data['bank_account']))       $rep->setBankAccount($data['bank_account']);

        $this->representationRepo->save($rep);

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

    #[OA\Get(
        path: '/api/v1/representation/{uuid}',
        summary: 'Get a representation 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: 'Representation 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/representation/{uuid}', methods: ['GET'])]
    public function get(string $uuid, #[CurrentUser] User $user): JsonResponse
    {
        $rep = $this->representationRepo->findByUuid($uuid);
        if ($rep === null) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'نماینده یافت نشد', 404);
        }

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

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

    #[OA\Patch(
        path: '/api/v1/representation/{uuid}',
        summary: 'Update a representation (own or admin)',
        security: [['bearerAuth' => []]],
        requestBody: new OA\RequestBody(
            required: false,
            content: new OA\JsonContent(
                properties: [
                    new OA\Property(property: 'full_name', type: 'string'),
                    new OA\Property(property: 'city_id', type: 'integer', nullable: true),
                    new OA\Property(property: 'bank_account', type: 'object', nullable: true),
                    new OA\Property(property: 'commission_percent', type: 'number', format: 'float'),
                    new OA\Property(property: 'active', type: 'boolean'),
                ]
            )
        ),
        parameters: [
            new OA\Parameter(name: 'uuid', in: 'path', required: true, schema: new OA\Schema(type: 'string')),
        ],
        responses: [
            new OA\Response(
                response: 200,
                description: 'Representation updated',
                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/representation/{uuid}', methods: ['PATCH'])]
    public function update(string $uuid, Request $request, #[CurrentUser] User $user): JsonResponse
    {
        $rep = $this->representationRepo->findByUuid($uuid);
        if ($rep === null) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'نماینده یافت نشد', 404);
        }

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

        $data = json_decode($request->getContent(), true) ?? [];
        if (array_key_exists('full_name', $data))          $rep->setFullName($data['full_name']);
        if (array_key_exists('city_id', $data))            $rep->setCityId($data['city_id'] ? (int)$data['city_id'] : null);
        if (array_key_exists('bank_account', $data))       $rep->setBankAccount($data['bank_account']);
        if (array_key_exists('commission_percent', $data)) $rep->setCommissionPercent((string)$data['commission_percent']);
        if (array_key_exists('active', $data))             $rep->setActive((bool)$data['active']);

        $this->representationRepo->save($rep);

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

    #[OA\Delete(
        path: '/api/v1/representation/{uuid}',
        summary: 'Delete a representation (ROLE_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: 'Representation deleted',
                content: new OA\JsonContent(
                    properties: [
                        new OA\Property(property: 'success', type: 'boolean', example: true),
                        new OA\Property(property: 'data', properties: [
                            new OA\Property(property: 'message', type: 'string'),
                        ], 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'),
        ]
    )]
    #[IsGranted('ROLE_ADMIN')]
    #[Route('/api/v1/representation/{uuid}', methods: ['DELETE'])]
    public function delete(string $uuid): JsonResponse
    {
        $rep = $this->representationRepo->findByUuid($uuid);
        if ($rep === null) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'نماینده یافت نشد', 404);
        }

        $this->representationRepo->remove($rep);
        return $this->success(['message' => 'نماینده با موفقیت حذف شد']);
    }

    // ── Dashboard: monthly stats ──────────────────────────────────────────────

    #[OA\Get(
        path: '/api/v1/representation/{uuid}/dashboard/monthly',
        summary: 'Get monthly dashboard stats for a representation',
        security: [['bearerAuth' => []]],
        parameters: [
            new OA\Parameter(name: 'uuid', in: 'path', required: true, schema: new OA\Schema(type: 'string')),
            new OA\Parameter(name: 'year', in: 'query', required: false, description: 'Jalali year', schema: new OA\Schema(type: 'integer')),
            new OA\Parameter(name: 'month', in: 'query', required: false, description: 'Jalali month (1–12)', schema: new OA\Schema(type: 'integer', minimum: 1, maximum: 12)),
        ],
        responses: [
            new OA\Response(
                response: 200,
                description: 'Monthly statistics',
                content: new OA\JsonContent(
                    properties: [
                        new OA\Property(property: 'success', type: 'boolean', example: true),
                        new OA\Property(property: 'data', properties: [
                            new OA\Property(property: 'period', properties: [
                                new OA\Property(property: 'jalali_year', type: 'integer'),
                                new OA\Property(property: 'jalali_month', type: 'integer'),
                            ], type: 'object'),
                            new OA\Property(property: 'stats', properties: [
                                new OA\Property(property: 'total_payments', type: 'integer'),
                                new OA\Property(property: 'total_revenue_rials', type: 'integer'),
                                new OA\Property(property: 'total_appointments', type: 'integer'),
                            ], type: 'object'),
                        ], 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/representation/{uuid}/dashboard/monthly', methods: ['GET'])]
    public function dashboardMonthly(string $uuid, Request $request, #[CurrentUser] User $user): JsonResponse
    {
        $rep = $this->representationRepo->findByUuid($uuid);
        if ($rep === null) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'نماینده یافت نشد', 404);
        }

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

        $jYear  = (int) ($request->query->get('year',  $this->jalali->jalaliYear(time())));
        $jMonth = (int) ($request->query->get('month', $this->jalali->jalaliMonth(time())));

        [$startTs, $endTs] = $this->jalali->jalaliMonthRange($jYear, $jMonth);

        return $this->success([
            'period' => ['jalali_year' => $jYear, 'jalali_month' => $jMonth],
            'stats'  => $this->buildStats($startTs, $endTs),
        ]);
    }

    #[OA\Get(
        path: '/api/v1/representation/{uuid}/dashboard/yearly',
        summary: 'Get yearly dashboard stats for a representation',
        security: [['bearerAuth' => []]],
        parameters: [
            new OA\Parameter(name: 'uuid', in: 'path', required: true, schema: new OA\Schema(type: 'string')),
            new OA\Parameter(name: 'year', in: 'query', required: false, description: 'Jalali year', schema: new OA\Schema(type: 'integer')),
        ],
        responses: [
            new OA\Response(
                response: 200,
                description: 'Yearly statistics broken down by month',
                content: new OA\JsonContent(
                    properties: [
                        new OA\Property(property: 'success', type: 'boolean', example: true),
                        new OA\Property(property: 'data', properties: [
                            new OA\Property(property: 'period', properties: [
                                new OA\Property(property: 'jalali_year', type: 'integer'),
                            ], type: 'object'),
                            new OA\Property(property: 'months', type: 'array', items: new OA\Items(
                                properties: [
                                    new OA\Property(property: 'jalali_month', type: 'integer'),
                                    new OA\Property(property: 'stats', properties: [
                                        new OA\Property(property: 'total_payments', type: 'integer'),
                                        new OA\Property(property: 'total_revenue_rials', type: 'integer'),
                                        new OA\Property(property: 'total_appointments', type: 'integer'),
                                    ], type: 'object'),
                                ]
                            )),
                            new OA\Property(property: 'totals', properties: [
                                new OA\Property(property: 'total_payments', type: 'integer'),
                                new OA\Property(property: 'total_revenue_rials', type: 'integer'),
                                new OA\Property(property: 'total_appointments', type: 'integer'),
                            ], type: 'object'),
                        ], 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/representation/{uuid}/dashboard/yearly', methods: ['GET'])]
    public function dashboardYearly(string $uuid, Request $request, #[CurrentUser] User $user): JsonResponse
    {
        $rep = $this->representationRepo->findByUuid($uuid);
        if ($rep === null) {
            return $this->error(ErrorCodes::ERR_NOT_FOUND_001, 'نماینده یافت نشد', 404);
        }

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

        $jYear = (int) ($request->query->get('year', $this->jalali->jalaliYear(time())));

        $months = [];
        for ($m = 1; $m <= 12; $m++) {
            [$mStart, $mEnd] = $this->jalali->jalaliMonthRange($jYear, $m);
            $months[]        = [
                'jalali_month' => $m,
                'stats'        => $this->buildStats($mStart, $mEnd),
            ];
        }

        [$startTs, $endTs] = $this->jalali->jalaliYearRange($jYear);

        return $this->success([
            'period' => ['jalali_year' => $jYear],
            'months' => $months,
            'totals' => $this->buildStats($startTs, $endTs),
        ]);
    }

    // ── Private ───────────────────────────────────────────────────────────────

    private function buildStats(int $startTs, int $endTs): array
    {
        $totalPayments = (int) $this->em->createQuery(
            'SELECT COUNT(p.id) FROM App\Payment\Entity\Payment p
             WHERE p.status = :status AND p.createdAt BETWEEN :start AND :end'
        )->setParameters(['status' => 'success', 'start' => $startTs, 'end' => $endTs])
         ->getSingleScalarResult();

        $totalRevenue = (int) ($this->em->createQuery(
            'SELECT SUM(p.amountRials) FROM App\Payment\Entity\Payment p
             WHERE p.status = :status AND p.createdAt BETWEEN :start AND :end'
        )->setParameters(['status' => 'success', 'start' => $startTs, 'end' => $endTs])
         ->getSingleScalarResult() ?? 0);

        $totalAppointments = (int) $this->em->createQuery(
            'SELECT COUNT(a.id) FROM App\Appointment\Entity\Appointment a
             WHERE a.createdAt BETWEEN :start AND :end'
        )->setParameters(['start' => $startTs, 'end' => $endTs])->getSingleScalarResult();

        return [
            'total_payments'      => $totalPayments,
            'total_revenue_rials' => $totalRevenue,
            'total_appointments'  => $totalAppointments,
        ];
    }
}
