<?php

declare(strict_types=1);

namespace App\Tests\Unit\Administration\Application\Service\Import;

use App\Administration\Application\Service\Import\CsvParser;
use App\Administration\Application\Service\Import\ImportFormatDetector;
use App\Administration\Application\Service\Import\ImportReport;
use App\Administration\Application\Service\Import\TeacherColumnMappingSuggester;
use App\Administration\Application\Service\Import\TeacherImportRowValidator;
use App\Administration\Domain\Model\Import\ImportRow;
use App\Administration\Domain\Model\Import\KnownImportFormat;
use App\Administration\Domain\Model\Import\TeacherImportField;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

/**
 * Test d'intégration de la chaîne complète d'import enseignants avec de vrais fichiers CSV.
 *
 * Parse → Détection format → Mapping → Validation → Rapport
 */
final class TeacherImportIntegrationTest extends TestCase
{
    #[Test]
    public function fullTeacherImportPipeline(): void
    {
        $filePath = $this->fixture('enseignants_simple.csv');

        // 1. Parser le fichier
        $parser = new CsvParser();
        $parseResult = $parser->parse($filePath);

        self::assertSame(3, $parseResult->totalRows());
        self::assertSame(['Nom', 'Prénom', 'Email', 'Matières', 'Classes'], $parseResult->columns);

        // 2. Détecter le format
        $detector = new ImportFormatDetector();
        $format = $detector->detecter($parseResult->columns);

        self::assertSame(KnownImportFormat::CUSTOM, $format);

        // 3. Suggérer le mapping
        $suggester = new TeacherColumnMappingSuggester();
        $suggestedMapping = $suggester->suggerer($parseResult->columns, $format);

        self::assertSame(TeacherImportField::LAST_NAME, $suggestedMapping['Nom']);
        self::assertSame(TeacherImportField::FIRST_NAME, $suggestedMapping['Prénom']);
        self::assertSame(TeacherImportField::EMAIL, $suggestedMapping['Email']);
        self::assertSame(TeacherImportField::SUBJECTS, $suggestedMapping['Matières']);
        self::assertSame(TeacherImportField::CLASSES, $suggestedMapping['Classes']);

        // 4. Appliquer le mapping sur les lignes
        $rows = [];
        $lineNumber = 1;

        foreach ($parseResult->rows as $rawData) {
            $mappedData = [];
            foreach ($suggestedMapping as $column => $field) {
                $mappedData[$field->value] = $rawData[$column] ?? '';
            }
            $rows[] = new ImportRow($lineNumber, $rawData, $mappedData);
            ++$lineNumber;
        }

        self::assertCount(3, $rows);
        self::assertSame('Dupont', $rows[0]->mappedData[TeacherImportField::LAST_NAME->value]);
        self::assertSame('Mathématiques', $rows[0]->mappedData[TeacherImportField::SUBJECTS->value]);
        self::assertSame('6A, 6B', $rows[0]->mappedData[TeacherImportField::CLASSES->value]);

        // 5. Valider les lignes
        $validator = new TeacherImportRowValidator();
        $validatedRows = $validator->validerTout($rows);

        foreach ($validatedRows as $row) {
            self::assertTrue($row->estValide(), "Ligne {$row->lineNumber} devrait être valide");
        }

        // 6. Générer le rapport
        $report = ImportReport::fromValidatedRows($validatedRows);

        self::assertSame(3, $report->totalRows);
        self::assertSame(3, $report->importedCount);
        self::assertSame(0, $report->errorCount);
    }

    #[Test]
    public function teacherImportWithInvalidRows(): void
    {
        $filePath = $this->fixture('enseignants_complet.csv');

        $parser = new CsvParser();
        $parseResult = $parser->parse($filePath);

        self::assertSame(8, $parseResult->totalRows());
        self::assertContains('Téléphone', $parseResult->columns);

        $detector = new ImportFormatDetector();
        $format = $detector->detecter($parseResult->columns);

        $suggester = new TeacherColumnMappingSuggester();
        $suggestedMapping = $suggester->suggerer($parseResult->columns, $format);

        // La colonne Téléphone ne doit pas être mappée
        self::assertArrayNotHasKey('Téléphone', $suggestedMapping);

        $rows = [];
        $lineNumber = 1;

        foreach ($parseResult->rows as $rawData) {
            $mappedData = [];
            foreach ($suggestedMapping as $column => $field) {
                $mappedData[$field->value] = $rawData[$column] ?? '';
            }
            $rows[] = new ImportRow($lineNumber, $rawData, $mappedData);
            ++$lineNumber;
        }

        $validator = new TeacherImportRowValidator();
        $validatedRows = $validator->validerTout($rows);

        $report = ImportReport::fromValidatedRows($validatedRows);

        // Moreau (ligne 5) : email manquant → erreur
        // Petit (ligne 6) : email invalide → erreur
        self::assertSame(8, $report->totalRows);
        self::assertSame(6, $report->importedCount);
        self::assertSame(2, $report->errorCount);

        // Vérifie les lignes en erreur
        $errorLines = array_map(
            static fn (ImportRow $row) => $row->lineNumber,
            $report->errorRows,
        );
        self::assertContains(5, $errorLines);
        self::assertContains(6, $errorLines);
    }

    #[Test]
    public function teacherImportCsvCommaFormat(): void
    {
        $filePath = $this->fixture('enseignants_comma.csv');

        $parser = new CsvParser();
        $parseResult = $parser->parse($filePath);

        self::assertSame(2, $parseResult->totalRows());
        self::assertSame(['Nom', 'Prénom', 'Email'], $parseResult->columns);

        $suggester = new TeacherColumnMappingSuggester();
        $suggestedMapping = $suggester->suggerer($parseResult->columns, KnownImportFormat::CUSTOM);

        // Pas de colonnes SUBJECTS ni CLASSES
        self::assertCount(3, $suggestedMapping);
        self::assertSame(TeacherImportField::LAST_NAME, $suggestedMapping['Nom']);
        self::assertSame(TeacherImportField::FIRST_NAME, $suggestedMapping['Prénom']);
        self::assertSame(TeacherImportField::EMAIL, $suggestedMapping['Email']);

        $rows = [];
        $lineNumber = 1;

        foreach ($parseResult->rows as $rawData) {
            $mappedData = [];
            foreach ($suggestedMapping as $column => $field) {
                $mappedData[$field->value] = $rawData[$column] ?? '';
            }
            $rows[] = new ImportRow($lineNumber, $rawData, $mappedData);
            ++$lineNumber;
        }

        $validator = new TeacherImportRowValidator();
        $validatedRows = $validator->validerTout($rows);

        $report = ImportReport::fromValidatedRows($validatedRows);

        self::assertSame(2, $report->totalRows);
        self::assertSame(2, $report->importedCount);
        self::assertSame(0, $report->errorCount);
    }

    #[Test]
    public function multiValueSubjectsWithPipeSeparator(): void
    {
        $filePath = $this->fixture('enseignants_complet.csv');

        $parser = new CsvParser();
        $parseResult = $parser->parse($filePath);

        // Ligne 3 : Bernard;Pierre;...;Physique | Chimie;4A
        $bernardRow = $parseResult->rows[2];
        self::assertSame('Physique | Chimie', $bernardRow['Matières']);
    }

    private function fixture(string $filename): string
    {
        return __DIR__ . '/../../../../../fixtures/import/' . $filename;
    }
}
