<?php

declare(strict_types=1);

namespace App\Administration\Application\Service\Import;

use App\Administration\Domain\Model\Import\KnownImportFormat;

/**
 * Détecte automatiquement le format d'import (Pronote, École Directe)
 * à partir des noms de colonnes.
 */
final readonly class ImportFormatDetector
{
    /**
     * Colonnes caractéristiques de Pronote.
     */
    private const array PRONOTE_COLUMNS = [
        'Élèves',
        'Né(e) le',
        'Sexe',
        'Classe de rattachement',
        'Adresse E-mail',
    ];

    /**
     * Colonnes caractéristiques d'École Directe.
     */
    private const array ECOLE_DIRECTE_COLUMNS = [
        'NOM',
        'PRENOM',
        'CLASSE',
        'DATE_NAISSANCE',
        'SEXE',
    ];

    /**
     * @param list<string> $columns Colonnes détectées dans le fichier
     */
    public function detecter(array $columns): KnownImportFormat
    {
        $normalizedColumns = array_map($this->normaliser(...), $columns);

        if ($this->matchesPronote($normalizedColumns)) {
            return KnownImportFormat::PRONOTE;
        }

        if ($this->matchesEcoleDirecte($normalizedColumns)) {
            return KnownImportFormat::ECOLE_DIRECTE;
        }

        return KnownImportFormat::CUSTOM;
    }

    /**
     * @param list<string> $normalizedColumns
     */
    private function matchesPronote(array $normalizedColumns): bool
    {
        $pronoteNormalized = array_map($this->normaliser(...), self::PRONOTE_COLUMNS);

        return $this->matchThreshold($normalizedColumns, $pronoteNormalized, 3);
    }

    /**
     * @param list<string> $normalizedColumns
     */
    private function matchesEcoleDirecte(array $normalizedColumns): bool
    {
        $ecoleDirecteNormalized = array_map($this->normaliser(...), self::ECOLE_DIRECTE_COLUMNS);

        return $this->matchThreshold($normalizedColumns, $ecoleDirecteNormalized, 3);
    }

    /**
     * @param list<string> $actualColumns
     * @param list<string> $expectedColumns
     */
    private function matchThreshold(array $actualColumns, array $expectedColumns, int $minMatches): bool
    {
        $matches = 0;

        foreach ($expectedColumns as $expected) {
            foreach ($actualColumns as $actual) {
                if ($actual === $expected) {
                    ++$matches;
                    break;
                }
            }
        }

        return $matches >= $minMatches;
    }

    private function normaliser(string $column): string
    {
        $normalized = mb_strtolower(trim($column));
        $normalized = str_replace(['_', '-', "'"], [' ', ' ', ' '], $normalized);

        /** @var string $result */
        $result = preg_replace('/\s+/', ' ', $normalized);

        return $result;
    }
}
