<?php

declare(strict_types=1);

namespace App\Administration\Application\Service\Import;

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

use function in_array;

/**
 * Suggère un mapping automatique des colonnes basé sur les noms de colonnes
 * et le format détecté.
 *
 * @see AC3: Mapping automatique proposé basé sur noms de colonnes
 */
final readonly class ColumnMappingSuggester
{
    /**
     * Mappings pré-configurés pour le format Pronote.
     *
     * @var array<string, StudentImportField>
     */
    private const array PRONOTE_MAPPING = [
        'élèves' => StudentImportField::FULL_NAME,
        'eleves' => StudentImportField::FULL_NAME,
        'né(e) le' => StudentImportField::BIRTH_DATE,
        'ne(e) le' => StudentImportField::BIRTH_DATE,
        'sexe' => StudentImportField::GENDER,
        'classe de rattachement' => StudentImportField::CLASS_NAME,
        'adresse e mail' => StudentImportField::EMAIL,
    ];

    private const array ECOLE_DIRECTE_MAPPING = [
        'nom' => StudentImportField::LAST_NAME,
        'prenom' => StudentImportField::FIRST_NAME,
        'classe' => StudentImportField::CLASS_NAME,
        'date naissance' => StudentImportField::BIRTH_DATE,
        'sexe' => StudentImportField::GENDER,
        'email' => StudentImportField::EMAIL,
        'numero' => StudentImportField::STUDENT_NUMBER,
    ];

    /**
     * Mapping générique par mots-clés.
     *
     * @var array<string, StudentImportField>
     */
    private const array GENERIC_KEYWORDS = [
        'élèves' => StudentImportField::FULL_NAME,
        'eleves' => StudentImportField::FULL_NAME,
        'nom' => StudentImportField::LAST_NAME,
        'last' => StudentImportField::LAST_NAME,
        'family' => StudentImportField::LAST_NAME,
        'surname' => StudentImportField::LAST_NAME,
        'prénom' => StudentImportField::FIRST_NAME,
        'prenom' => StudentImportField::FIRST_NAME,
        'first' => StudentImportField::FIRST_NAME,
        'given' => StudentImportField::FIRST_NAME,
        'classe' => StudentImportField::CLASS_NAME,
        'class' => StudentImportField::CLASS_NAME,
        'groupe' => StudentImportField::CLASS_NAME,
        'email' => StudentImportField::EMAIL,
        'mail' => StudentImportField::EMAIL,
        'courriel' => StudentImportField::EMAIL,
        'naissance' => StudentImportField::BIRTH_DATE,
        'birth' => StudentImportField::BIRTH_DATE,
        'date' => StudentImportField::BIRTH_DATE,
        'sexe' => StudentImportField::GENDER,
        'genre' => StudentImportField::GENDER,
        'gender' => StudentImportField::GENDER,
        'numéro' => StudentImportField::STUDENT_NUMBER,
        'numero' => StudentImportField::STUDENT_NUMBER,
        'number' => StudentImportField::STUDENT_NUMBER,
        'matricule' => StudentImportField::STUDENT_NUMBER,
    ];

    /**
     * Suggère un mapping pour les colonnes données.
     *
     * @param list<string>      $columns        Colonnes détectées dans le fichier
     * @param KnownImportFormat $detectedFormat Format détecté
     *
     * @return array<string, StudentImportField> Mapping suggéré (colonne → champ)
     */
    public function suggerer(array $columns, KnownImportFormat $detectedFormat): array
    {
        return match ($detectedFormat) {
            KnownImportFormat::PRONOTE => $this->mapperAvecReference($columns, self::PRONOTE_MAPPING),
            KnownImportFormat::ECOLE_DIRECTE => $this->mapperAvecReference($columns, self::ECOLE_DIRECTE_MAPPING),
            KnownImportFormat::CUSTOM => $this->mapperGenerique($columns),
        };
    }

    /**
     * @param list<string>                      $columns
     * @param array<string, StudentImportField> $reference
     *
     * @return array<string, StudentImportField>
     */
    private function mapperAvecReference(array $columns, array $reference): array
    {
        $normalizedReference = [];
        foreach ($reference as $key => $field) {
            $normalizedReference[$this->normaliser($key)] = $field;
        }

        $mapping = [];
        $usedFields = [];

        foreach ($columns as $column) {
            $normalized = $this->normaliser($column);

            if (isset($normalizedReference[$normalized]) && !in_array($normalizedReference[$normalized], $usedFields, true)) {
                $mapping[$column] = $normalizedReference[$normalized];
                $usedFields[] = $normalizedReference[$normalized];
            }
        }

        return $mapping;
    }

    /**
     * @param list<string> $columns
     *
     * @return array<string, StudentImportField>
     */
    private function mapperGenerique(array $columns): array
    {
        $mapping = [];
        $usedFields = [];

        foreach ($columns as $column) {
            $normalized = $this->normaliser($column);

            foreach (self::GENERIC_KEYWORDS as $keyword => $field) {
                if (str_contains($normalized, $keyword) && !in_array($field, $usedFields, true)) {
                    $mapping[$column] = $field;
                    $usedFields[] = $field;
                    break;
                }
            }
        }

        return $mapping;
    }

    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;
    }
}
