<?php

namespace App\Controller\Admin;

use App\Entity\AdvertPayment;
use App\Entity\Echeancier;
use App\Entity\EcheancierLine;
use App\Entity\Facture;
use App\Entity\FacturePrestataire;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\Component\Security\Http\Attribute\IsGranted;

#[Route('/admin/stats', name: 'app_admin_stats_')]
#[IsGranted('ROLE_ROOT')]
class StatsController extends AbstractController
{
    private const STATUS_SURPLUS = 'Surplus';
    private const STATUS_RENTABLE = 'Rentable';
    private const STATUS_NEGATIF = 'Negatif';
    private const DQL_BETWEEN_DATES = 'f.createdAt BETWEEN :from AND :to';
    private const DQL_IS_PAID = 'f.isPaid = true';
    private const COLOR_GOLD = '#fabf04';

    public function __construct(
        private EntityManagerInterface $em,
    ) {
    }

    #[Route('', name: 'index')]
    public function index(Request $request): Response
    {
        $period = $request->query->getString('period', 'current');
        $now = new \DateTimeImmutable();

        if ('custom' === $period) {
            $dateFrom = $request->query->getString('from', $now->format('Y-m-01'));
            $dateTo = $request->query->getString('to', $now->format('Y-m-d'));
        } elseif ('current' === $period) {
            $dateFrom = $now->format('Y-m-01');
            $dateTo = $now->format('Y-m-d');
        } else {
            $months = (int) $period;
            $dateFrom = $now->modify('-'.$months.' months')->format('Y-m-01');
            $dateTo = $now->format('Y-m-d');
        }

        $from = new \DateTimeImmutable($dateFrom);
        $to = new \DateTimeImmutable($dateTo.' 23:59:59');

        // CA dynamique depuis les factures payees
        $factureStats = $this->getFactureStats($from, $to);

        // CA dynamique depuis les paiements Stripe (AdvertPayment)
        $paymentStats = $this->getPaymentStats($from, $to);

        // Stats globales
        $totalCaHt = (float) $factureStats['totalHt'];
        $totalCaTva = (float) $factureStats['totalTva'];
        $totalCaTtc = (float) $factureStats['totalTtc'];
        $commissionStripe = $totalCaTtc * 0.015;

        // Cout prestataire dynamique depuis les factures prestataires de la periode
        $coutPrestataire = $this->getCoutPrestataire($from, $to);
        $coutInfra = 80.0;
        $coutFonctionnement = $coutInfra + $coutPrestataire;
        $coutTotal = $coutFonctionnement + $commissionStripe;

        $globalStats = [
            'ca_ht' => $totalCaHt,
            'ca_tva' => $totalCaTva,
            'ca_ttc' => $totalCaTtc,
            'commission_stripe' => $commissionStripe,
            'cout_infra' => $coutInfra,
            'cout_prestataire' => $coutPrestataire,
            'cout_fonctionnement' => $coutFonctionnement,
            'marge_nette' => $totalCaHt - $coutTotal,
            'status' => $this->resolveStatus($totalCaHt - $coutTotal, $totalCaHt),
            'factures_emises' => $factureStats['nbTotal'],
            'factures_payees' => $factureStats['nbPaid'],
            'factures_impayees' => $factureStats['nbTotal'] - $factureStats['nbPaid'],
            'montant_emis' => $factureStats['totalEmis'],
            'montant_paye' => $factureStats['totalTtc'],
            'montant_impaye' => (float) $factureStats['totalEmis'] - (float) $factureStats['totalTtc'],
        ];

        // Evolution mensuelle (6 derniers mois)
        $monthlyEvolution = $this->getMonthlyEvolution();

        // Services dynamiques depuis les lignes de factures payees
        $services = $this->getServiceStats($from, $to);

        // Echeanciers en cours avec echeances impayees
        $echeancierStats = $this->getEcheancierStats();

        return $this->render('admin/stats/index.html.twig', [
            'period' => $period,
            'dateFrom' => $dateFrom,
            'dateTo' => $dateTo,
            'global' => $globalStats,
            'services' => $services,
            'evolution' => $monthlyEvolution,
            'payments' => $paymentStats,
            'echeancierStats' => $echeancierStats,
        ]);
    }

    /**
     * @return array{totalHt: string, totalTva: string, totalTtc: string, totalEmis: float, nbTotal: int, nbPaid: int}
     */
    private function getFactureStats(\DateTimeImmutable $from, \DateTimeImmutable $to): array
    {
        $qb = $this->em->createQueryBuilder();

        // Toutes les factures de la periode
        $allFactures = $qb->select('f')
            ->from(Facture::class, 'f')
            ->where(self::DQL_BETWEEN_DATES)
            ->setParameter('from', $from)
            ->setParameter('to', $to)
            ->getQuery()
            ->getResult();

        $totalHt = 0.0;
        $totalTva = 0.0;
        $totalTtc = 0.0;
        $totalEmis = 0.0;
        $nbPaid = 0;

        foreach ($allFactures as $facture) {
            $totalEmis += (float) $facture->getTotalTtc();

            if ($facture->isPaid()) {
                $totalHt += (float) $facture->getTotalHt();
                $totalTva += (float) $facture->getTotalTva();
                $totalTtc += (float) $facture->getTotalTtc();
                ++$nbPaid;
            }
        }

        return [
            'totalHt' => number_format($totalHt, 2, '.', ''),
            'totalTva' => number_format($totalTva, 2, '.', ''),
            'totalTtc' => number_format($totalTtc, 2, '.', ''),
            'totalEmis' => $totalEmis,
            'nbTotal' => \count($allFactures),
            'nbPaid' => $nbPaid,
        ];
    }

    /**
     * @return array{total: string, count: int}
     */
    private function getPaymentStats(\DateTimeImmutable $from, \DateTimeImmutable $to): array
    {
        $payments = $this->em->createQueryBuilder()
            ->select('p')
            ->from(AdvertPayment::class, 'p')
            ->where('p.createdAt BETWEEN :from AND :to')
            ->andWhere('p.type = :type')
            ->setParameter('from', $from)
            ->setParameter('to', $to)
            ->setParameter('type', AdvertPayment::TYPE_SUCCESS)
            ->getQuery()
            ->getResult();

        $total = 0.0;
        foreach ($payments as $p) {
            $total += (float) $p->getAmount();
        }

        return [
            'total' => number_format($total, 2, '.', ''),
            'count' => \count($payments),
        ];
    }

    /**
     * @return list<array{month: string, ca_ht: float, ca_ttc: float}>
     */
    private function getMonthlyEvolution(): array
    {
        $result = [];
        $now = new \DateTimeImmutable();

        for ($i = 5; $i >= 0; --$i) {
            $monthStart = $now->modify('-'.$i.' months')->modify('first day of this month');
            $monthEnd = $monthStart->modify('last day of this month 23:59:59');

            $factures = $this->em->createQueryBuilder()
                ->select('f')
                ->from(Facture::class, 'f')
                ->where(self::DQL_BETWEEN_DATES)
                ->andWhere(self::DQL_IS_PAID)
                ->setParameter('from', $monthStart)
                ->setParameter('to', $monthEnd)
                ->getQuery()
                ->getResult();

            $caHt = 0.0;
            $caTtc = 0.0;
            foreach ($factures as $f) {
                $caHt += (float) $f->getTotalHt();
                $caTtc += (float) $f->getTotalTtc();
            }

            $result[] = [
                'month' => $monthStart->format('M Y'),
                'ca_ht' => $caHt,
                'ca_ttc' => $caTtc,
            ];
        }

        return $result;
    }

    private const SERVICE_CONFIG = [
        'website' => ['name' => 'E-Site', 'color' => self::COLOR_GOLD, 'cout' => 150.00, 'group' => 'esite'],
        'hosting' => ['name' => 'E-Site', 'color' => self::COLOR_GOLD, 'cout' => 0.00, 'group' => 'esite'],
        'maintenance' => ['name' => 'E-Site', 'color' => self::COLOR_GOLD, 'cout' => 0.00, 'group' => 'esite'],
        'esymail' => ['name' => 'E-Mail', 'color' => '#dc2626', 'cout' => 70.00, 'group' => 'esymail'],
        'ndd' => ['name' => 'Nom de domaine', 'color' => '#64748b', 'cout' => 0.00, 'cout_par_ligne' => 15.00, 'group' => 'ndd'],
        'other' => ['name' => 'Autre', 'color' => '#6b7280', 'cout' => 0.00, 'group' => 'other'],
    ];

    /**
     * @return list<array{name: string, color: string, ca_ht: float, cout: float, marge: float, status: string, clients: int}>
     */
    private function getServiceStats(\DateTimeImmutable $from, \DateTimeImmutable $to): array
    {
        $factures = $this->em->createQueryBuilder()
            ->select('f')
            ->from(Facture::class, 'f')
            ->where(self::DQL_BETWEEN_DATES)
            ->andWhere(self::DQL_IS_PAID)
            ->setParameter('from', $from)
            ->setParameter('to', $to)
            ->getQuery()
            ->getResult();

        $raw = $this->groupServiceLines($factures);
        $grouped = $this->mergeServiceGroups($raw);

        $services = [];
        foreach ($grouped as $data) {
            $marge = $data['ca_ht'] - $data['cout'];
            $services[] = [
                'name' => $data['name'],
                'color' => $data['color'],
                'ca_ht' => $data['ca_ht'],
                'cout' => $data['cout'],
                'marge' => $marge,
                'status' => $this->resolveServiceStatus($data['ca_ht'], $marge),
                'clients' => \count($data['customers']),
            ];
        }

        usort($services, fn ($a, $b) => $b['ca_ht'] <=> $a['ca_ht']);

        return $services;
    }

    /**
     * @param list<Facture> $factures
     *
     * @return array<string, array{ca_ht: float, customers: array<int, true>, lines: int}>
     */
    private function groupServiceLines(array $factures): array
    {
        $raw = [];
        foreach (self::SERVICE_CONFIG as $type => $config) {
            $raw[$type] = ['ca_ht' => 0.0, 'customers' => [], 'lines' => 0];
        }

        foreach ($factures as $facture) {
            $customerId = $facture->getCustomer()?->getId();
            foreach ($facture->getLines() as $line) {
                $type = $line->getType() ?? 'other';
                if (!isset($raw[$type])) {
                    $type = 'other';
                }
                $raw[$type]['ca_ht'] += (float) $line->getPriceHt();
                $title = $line->getTitle();
                if ('ndd' !== $type || str_contains($title, 'Renouvellement') || str_contains($title, 'Depot')) {
                    ++$raw[$type]['lines'];
                }
                if (null !== $customerId) {
                    $raw[$type]['customers'][$customerId] = true;
                }
            }
        }

        return $raw;
    }

    /**
     * @param array<string, array{ca_ht: float, customers: array<int, true>, lines: int}> $raw
     *
     * @return array<string, array{name: string, color: string, ca_ht: float, cout: float, customers: array<int, true>}>
     */
    private function mergeServiceGroups(array $raw): array
    {
        $grouped = [];
        foreach (self::SERVICE_CONFIG as $type => $config) {
            $group = $config['group'];
            if (!isset($grouped[$group])) {
                $grouped[$group] = ['name' => $config['name'], 'color' => $config['color'], 'ca_ht' => 0.0, 'cout' => 0.0, 'customers' => []];
            }
            $grouped[$group]['ca_ht'] += $raw[$type]['ca_ht'];
            $grouped[$group]['cout'] += $config['cout'] + (($config['cout_par_ligne'] ?? 0.0) * $raw[$type]['lines']);
            $grouped[$group]['customers'] += $raw[$type]['customers'];
        }

        return $grouped;
    }

    private function resolveServiceStatus(float $caHt, float $marge): string
    {
        if ($caHt <= 0) {
            return 'Inactif';
        }

        return $marge >= 0 ? 'Rentable' : 'Negatif';
    }

    private function getCoutPrestataire(\DateTimeImmutable $from, \DateTimeImmutable $to): float
    {
        $factures = $this->em->createQueryBuilder()
            ->select('fp')
            ->from(FacturePrestataire::class, 'fp')
            ->where('fp.createdAt BETWEEN :from AND :to')
            ->setParameter('from', $from)
            ->setParameter('to', $to)
            ->getQuery()
            ->getResult();

        $total = 0.0;
        foreach ($factures as $fp) {
            $total += (float) $fp->getMontantHt();
        }

        return $total;
    }

    /**
     * @return array{nbEcheanciers: int, nbEcheancesImpayees: int, montantImpaye: float, echeanciers: list<array{reference: string, customer: string, restant: float, nbPending: int, id: int}>}
     */
    private function getEcheancierStats(): array
    {
        $echeanciers = $this->em->createQuery(
            'SELECT e FROM App\Entity\Echeancier e
             WHERE e.state IN (:states)
             ORDER BY e.createdAt DESC'
        )
            ->setParameter('states', [Echeancier::STATE_ACTIVE, Echeancier::STATE_PENDING_SETUP, Echeancier::STATE_SIGNED])
            ->getResult();

        $nbEcheancesImpayees = 0;
        $montantImpaye = 0.0;
        $list = [];

        /** @var Echeancier $echeancier */
        foreach ($echeanciers as $echeancier) {
            $nbPending = 0;
            $restant = 0.0;

            foreach ($echeancier->getLines() as $line) {
                if (EcheancierLine::STATE_OK !== $line->getState()) {
                    ++$nbPending;
                    $restant += (float) $line->getAmount();
                }
            }

            if ($nbPending > 0) {
                $nbEcheancesImpayees += $nbPending;
                $montantImpaye += $restant;

                $list[] = [
                    'id' => $echeancier->getId(),
                    'reference' => $echeancier->getReference(),
                    'customer' => $echeancier->getCustomer()->getFullName(),
                    'restant' => $restant,
                    'nbPending' => $nbPending,
                ];
            }
        }

        return [
            'nbEcheanciers' => \count($list),
            'nbEcheancesImpayees' => $nbEcheancesImpayees,
            'montantImpaye' => $montantImpaye,
            'echeanciers' => $list,
        ];
    }

    private function resolveStatus(float $margeNette, float $caHt): string
    {
        if ($caHt <= 0) {
            return self::STATUS_RENTABLE;
        }

        $ratio = $margeNette / $caHt;

        if ($ratio > 0.3) {
            return self::STATUS_SURPLUS;
        }

        return $margeNette >= 0 ? self::STATUS_RENTABLE : self::STATUS_NEGATIF;
    }
}
