<?php

declare(strict_types=1);

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

use App\Administration\Application\Service\Import\ColumnMappingSuggester;
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\ImportRowValidator;
use App\Administration\Domain\Model\Import\ImportRow;
use App\Administration\Domain\Model\Import\KnownImportFormat;
use App\Administration\Domain\Model\Import\StudentImportField;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

/**
 * Test d'intégration de la chaîne complète d'import avec un vrai fichier Pronote.
 *
 * Parse → Détection format → Mapping → Validation → Rapport
 */
final class PronoteImportIntegrationTest extends TestCase
{
    #[Test]
    public function fullPronoteImportPipeline(): void
    {
        $filePath = __DIR__ . '/../../../../../fixtures/import/eleves_pronote.csv';

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

        self::assertSame(27, $parseResult->totalRows());
        self::assertContains('Élèves', $parseResult->columns);

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

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

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

        self::assertSame(StudentImportField::FULL_NAME, $suggestedMapping['Élèves']);
        self::assertSame(StudentImportField::BIRTH_DATE, $suggestedMapping['Né(e) le']);
        self::assertSame(StudentImportField::GENDER, $suggestedMapping['Sexe']);
        self::assertSame(StudentImportField::EMAIL, $suggestedMapping['Adresse E-mail']);

        // 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(27, $rows);
        self::assertSame('BERTHE Alexandre', $rows[0]->valeurChamp(StudentImportField::FULL_NAME));

        // 5. Valider les lignes (pas de vérification de classes existantes)
        $validator = new ImportRowValidator();
        $validatedRows = $validator->validerTout($rows);

        // Toutes les lignes devraient être valides car FULL_NAME → LAST_NAME + FIRST_NAME
        $validCount = 0;
        $errorCount = 0;

        foreach ($validatedRows as $row) {
            if ($row->estValide()) {
                ++$validCount;
            } else {
                ++$errorCount;
            }
        }

        // Certaines lignes ont une classe vide → erreur sur className obligatoire
        self::assertGreaterThan(0, $validCount + $errorCount);
        self::assertSame(27, $validCount + $errorCount);

        // Vérifions que le splitFullName a bien fonctionné sur la première ligne
        $firstRow = $validatedRows[0];
        self::assertSame('BERTHE', $firstRow->valeurChamp(StudentImportField::LAST_NAME));
        self::assertSame('Alexandre', $firstRow->valeurChamp(StudentImportField::FIRST_NAME));

        // Vérifions Jean-Philippe (prénom composé)
        $jeanPhilippe = null;
        foreach ($validatedRows as $row) {
            if (str_contains($row->valeurChamp(StudentImportField::FULL_NAME) ?? '', 'OLIVIER')) {
                $jeanPhilippe = $row;
                break;
            }
        }
        self::assertNotNull($jeanPhilippe);
        self::assertSame('OLIVIER', $jeanPhilippe->valeurChamp(StudentImportField::LAST_NAME));
        self::assertSame('Jean-Philippe', $jeanPhilippe->valeurChamp(StudentImportField::FIRST_NAME));

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

        self::assertSame(27, $report->totalRows);
        self::assertSame($validCount, $report->importedCount);
        self::assertSame($errorCount, $report->errorCount);
    }

    #[Test]
    public function pronoteClasseDeRattachementIsEmpty(): void
    {
        $filePath = __DIR__ . '/../../../../../fixtures/import/eleves_pronote.csv';

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

        // Dans le fichier Pronote de démo, "Classe de rattachement" est vide pour tous
        foreach ($parseResult->rows as $row) {
            self::assertSame('', $row['Classe de rattachement']);
        }
    }

    #[Test]
    public function pronoteRowsWithEmptyClassAreInvalid(): void
    {
        $validator = new ImportRowValidator();
        $row = new ImportRow(
            lineNumber: 1,
            rawData: ['Élèves' => 'BERTHE Alexandre', 'Classe de rattachement' => ''],
            mappedData: [
                'fullName' => 'BERTHE Alexandre',
                'className' => '',
                'birthDate' => '07/07/2011',
                'gender' => 'Masculin',
                'email' => 'alexandre.berthe@fournisseur.fr',
            ],
        );

        $result = $validator->valider($row);

        // className est obligatoire → erreur
        self::assertFalse($result->estValide());
        self::assertSame('className', $result->errors[0]->column);

        // Mais le nom a bien été splitté
        self::assertSame('BERTHE', $result->valeurChamp(StudentImportField::LAST_NAME));
        self::assertSame('Alexandre', $result->valeurChamp(StudentImportField::FIRST_NAME));
    }
}
