<?php

namespace App\Service;

use App\Repository\ConcessionRepository;
use OpenSpout\Reader\CSV\Reader as CsvReader;
use OpenSpout\Reader\XLSX\Reader as XlsxReader;

/**
 * Importe le référentiel des concessions depuis un fichier Excel (.xlsx) ou CSV :
 * colonne A = ID_CONCESSION (identifiant stable du DMS), colonne B = nom, une par ligne.
 * Une ligne d'en-tête (ID_CONCESSION / NOM…) est détectée et ignorée automatiquement.
 */
final class ConcessionImporter
{
    private const ID_HEADERS = ['idconcession', 'concessionid', 'codeconcession', 'idconc', 'id', 'code'];
    private const NAME_HEADERS = ['nom', 'nomconcession', 'concession', 'libelle', 'name'];

    public function __construct(
        private readonly ConcessionRepository $repository,
    ) {
    }

    /**
     * @param callable(int): void|null $onProgress appelé périodiquement avec le nombre de concessions lues
     *
     * @return int Nombre de concessions enregistrées
     *
     * @throws \RuntimeException si le format est invalide ou le fichier vide
     */
    public function importFromFile(string $path, string $extension, bool $skipHeader, ?callable $onProgress = null): int
    {
        $pairs = $this->readPairs($path, $extension, $skipHeader, $onProgress);

        if ([] === $pairs) {
            throw new \RuntimeException('Aucune concession trouvée. Le fichier doit contenir ID_CONCESSION en colonne A et le nom en colonne B.');
        }

        return $this->repository->replaceAll($pairs);
    }

    /**
     * @param callable(int): void|null $onProgress
     *
     * @return list<array{id: string, name: string}>
     */
    private function readPairs(string $path, string $extension, bool $skipHeader, ?callable $onProgress = null): array
    {
        $reader = match (strtolower($extension)) {
            'xlsx' => new XlsxReader(),
            'csv' => new CsvReader(),
            default => throw new \RuntimeException('Format non supporté. Utilisez un fichier .xlsx ou .csv.'),
        };
        $reader->open($path);

        $pairs = [];
        try {
            foreach ($reader->getSheetIterator() as $sheet) {
                $rowIndex = 0;
                foreach ($sheet->getRowIterator() as $row) {
                    ++$rowIndex;
                    $cells = $row->toArray();
                    $id = $this->cell($cells, 0);
                    $name = $this->cell($cells, 1);

                    if (1 === $rowIndex && ($skipHeader || $this->isHeaderRow($id, $name))) {
                        continue;
                    }
                    if ('' === $id || '' === $name) {
                        continue; // ligne incomplète → ignorée
                    }
                    $pairs[] = ['id' => $id, 'name' => $name];
                    if (null !== $onProgress && 0 === \count($pairs) % 100) {
                        $onProgress(\count($pairs));
                    }
                }

                break; // première feuille uniquement
            }
        } finally {
            $reader->close();
        }

        return $pairs;
    }

    private function isHeaderRow(string $a, string $b): bool
    {
        return \in_array(StockImporter::normalize($a), self::ID_HEADERS, true)
            || \in_array(StockImporter::normalize($b), self::NAME_HEADERS, true);
    }

    /**
     * @param array<int, mixed> $cells
     */
    private function cell(array $cells, int $index): string
    {
        $value = $cells[$index] ?? null;
        // IDs numériques : Excel renvoie des int/float → "123" et pas "123.0"
        if (\is_int($value)) {
            return (string) $value;
        }
        if (\is_float($value) && $value == (int) $value) {
            return (string) (int) $value;
        }

        return trim((string) $value);
    }
}
