<?php

namespace Myvetshop\Module\Clinique\Accounting\Export\PostProcess;

use Myvetshop\Module\Clinique\Accounting\Export\Model\ExportLine;

class RegroupByDayPostProcessor implements GlobalPostProcessorInterface
{
    /**
     * @var array<string, list<ExportLine>>
     */
    private array $lines = [];

    public function computeLineRegroupKey(ExportLine $line): string
    {
        $preventRegroup = false;

        // Les comptes 411000000 sont regroupés (sous condition)
        if (
            $line->getAccount() === '411000000'
            && $line->getAuxiliary() === '4110001'
        ) {
            // Les comptes 411000000 ne sont pas regroupés si s'il s'agit d'un remboursement
            // Ou si c'est une vente par stripe
            $preventRegroup = $line->getEntitled() === 'Remboursement internet CB'
                || ($line->getEntitled() === 'Vente internet' && $line->getPaymentMethod() === 'Card via Stripe');
        }

        return $line->getDate()->format('Y-m-d')
            . '-' . $line->getEntitled()
            . '-' . $line->getPaymentMethod()
            . '-' . $line->getAccount()
            . '-' . $line->getAuxiliary()
            . ($preventRegroup ? '-' . $line->getDocNumber() . '-' . \uniqid('', true) : '');
    }

    /**
     * Méthode permettant le tri du tableau en sortie
     */
    public function compareExportLines(ExportLine $lineA, ExportLine $lineB): int
    {
        return \strcmp($this->computeLineRegroupKey($lineA), $this->computeLineRegroupKey($lineB));
    }

    /**
     * @param list<ExportLine> $lines
     */
    public function addLines(array $lines): void
    {
        // Ajoute les lignes dans les groupes existants
        $this->lines = \array_reduce(
            $lines,
            function (array $carry, ExportLine $line): array {
                $carry[$this->computeLineRegroupKey($line)][] = $line;

                return $carry;
            },
            $this->lines
        );

        // Sommes partielles par groupe (chaque entrée de $this->lines ne contient alors plus qu'une seule ligne)
        $this->lines = \array_map(
            fn (array $lines) => [$this->sumLines($lines)],
            $this->lines,
        );
    }

    /**
     * @param list<ExportLine> $lines
     */
    public function sumLines(array $lines): ExportLine
    {
        if (1 === \count($lines) && $lines[0]->getAccount() === '411000000' && $lines[0]->getAuxiliary() === '4110001') {
            return $lines[0];
        }

        $entitled = $lines[0]->getEntitled();
        $shortDate = $lines[0]->getDate()->format(' d/m');
        if (!strpos($entitled, $shortDate)) {
            $entitled .= $shortDate;
        }

        $rawData = \array_reduce(
            $lines,
            function (array $carry, ExportLine $line): array {
                $carry['debit'] += $line->getDebit();
                $carry['credit'] += $line->getCredit();

                return $carry;
            },
            [
                'date' => $lines[0]->getDate(),
                'journal' => $lines[0]->getJournal(),
                'account' => $lines[0]->getAccount(),
                'auxiliary' => $lines[0]->getAuxiliary(),
                'entitled' => $entitled,
                'docNumber' => '',
                'debit' => 0.0,
                'credit' => 0.0,
                'paymentMethod' => $lines[0]->getPaymentMethod(),
            ]
        );

        return new ExportLine(
            $rawData['date'],
            $rawData['journal'],
            $rawData['account'],
            $rawData['auxiliary'],
            $rawData['entitled'],
            $rawData['docNumber'],
            \round($rawData['debit'], 2),
            \round($rawData['credit'], 2),
            $rawData['paymentMethod']
        );
    }

    /**
     * @return list<ExportLine>
     */
    public function getLines(): array
    {
        $ret = \array_values(
            \array_map(
                fn (array $lines): ExportLine => $lines[0],
                $this->lines
            )
        );

        \usort($ret, [$this, 'compareExportLines']);

        return $ret;
    }

    public function reset(): void
    {
        $this->lines = [];
    }
}
