<?php

namespace App\Service;

use App\Entity\Facture;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;

/**
 * Helpers utilitaires pour les exports comptables (periodes, formats, labels).
 */
class ComptaHelperService
{
    public const LABEL_CLIENT_DELETED = 'Client supprime';

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

    /**
     * @return array{\DateTimeImmutable, \DateTimeImmutable}
     */
    public function resolvePeriod(Request $request): array
    {
        $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 ('previous' === $period) {
            $prev = $now->modify('first day of last month');
            $dateFrom = $prev->format('Y-m-01');
            $dateTo = $prev->modify('last day of this month')->format('Y-m-d');
        } else {
            $dateFrom = $now->format('Y-m-01');
            $dateTo = $now->format('Y-m-d');
        }

        return [
            new \DateTimeImmutable($dateFrom),
            new \DateTimeImmutable($dateTo.' 23:59:59'),
        ];
    }

    /**
     * @param list<array<string, string>> $rows
     */
    public function exportResponse(array $rows, string $filename, string $format): Response
    {
        if ('json' === $format) {
            return new JsonResponse($rows, 200, [
                'Content-Disposition' => 'attachment; filename="'.$filename.'.json"',
            ]);
        }

        // @codeCoverageIgnoreStart
        $response = new StreamedResponse(function () use ($rows) {
            $handle = fopen('php://output', 'w');
            fwrite($handle, "\xEF\xBB\xBF");

            if (!empty($rows)) {
                fputcsv($handle, array_keys($rows[0]), ';');
                foreach ($rows as $row) {
                    fputcsv($handle, $row, ';');
                }
            }

            fclose($handle);
        });
        // @codeCoverageIgnoreEnd

        $response->headers->set('Content-Type', 'text/csv; charset=UTF-8');
        $response->headers->set('Content-Disposition', 'attachment; filename="'.$filename.'.csv"');

        return $response;
    }

    /**
     * @return list<Facture>
     */
    public function getFactures(\DateTimeImmutable $from, \DateTimeImmutable $to): array
    {
        return $this->em->createQueryBuilder()
            ->select('f')
            ->from(Facture::class, 'f')
            ->where('f.createdAt BETWEEN :from AND :to')
            ->andWhere('f.state != :cancel')
            ->setParameter('from', $from)
            ->setParameter('to', $to)
            ->setParameter('cancel', Facture::STATE_CANCEL)
            ->orderBy('f.createdAt', 'ASC')
            ->getQuery()
            ->getResult();
    }

    public function resolveCompteBanque(?string $method): string
    {
        return match ($method) {
            'card' => '512100',
            'sepa_debit' => '512100',
            'paypal' => '512200',
            'klarna' => '512300',
            'transfer', 'virement' => '512000',
            default => '512000',
        };
    }

    public function resolveLibelleBanque(?string $method): string
    {
        return match ($method) {
            'card' => 'Stripe CB',
            'sepa_debit' => 'Stripe SEPA',
            'paypal' => 'PayPal',
            'klarna' => 'Klarna',
            'transfer', 'virement' => 'Virement bancaire',
            default => 'Banque',
        };
    }

    public function resolveTrancheAge(int $jours): string
    {
        $tranches = [
            30 => '0-30 jours',
            60 => '31-60 jours',
            90 => '61-90 jours',
        ];

        foreach ($tranches as $limit => $label) {
            if ($jours <= $limit) {
                return $label;
            }
        }

        return '+90 jours';
    }

    /**
     * @return array{string, string} [codeComptable, raisonSociale]
     */
    public function resolveCustomerInfo(?object $customer): array
    {
        $codeComptable = $customer?->getCodeComptable() ?? 'DIVERS';
        $raisonSociale = $customer?->getRaisonSociale()
            ?? ($customer ? $customer->getFirstName().' '.$customer->getLastName() : self::LABEL_CLIENT_DELETED);

        return [$codeComptable, $raisonSociale];
    }

    /**
     * @return array<string, array{types: list<string>, name: string}>
     */
    public function getServiceGroups(): array
    {
        return [
            'esite' => ['types' => ['website', 'hosting', 'maintenance'], 'name' => 'E-Site'],
            'esymail' => ['types' => ['esymail'], 'name' => 'E-Mail'],
            'ndd' => ['types' => ['ndd'], 'name' => 'Nom de domaine'],
            'other' => ['types' => ['other'], 'name' => 'Autre'],
        ];
    }

    /**
     * @param array<string, mixed>                            $group
     * @param array<string, array{ca_ht: float, lines: int}> $grouped
     *
     * @return array{float, float} [caHt, cout]
     */
    public function aggregateServiceGroup(array $group, array $grouped): array
    {
        $caHt = 0.0;
        $cout = 0.0;

        foreach ($group['types'] as $type) {
            $caHt += $grouped[$type]['ca_ht'];
            $config = ComptaExportService::SERVICE_COSTS[$type];
            $cout += $config['cout'] + (($config['cout_par_ligne'] ?? 0.0) * $grouped[$type]['lines']);
        }

        return [$caHt, $cout];
    }

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

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