<?php

declare(strict_types=1);

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

use App\Administration\Application\Service\Import\TeacherImportRowValidator;
use App\Administration\Domain\Model\Import\ImportRow;
use App\Administration\Domain\Model\Import\TeacherImportField;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class TeacherImportRowValidatorTest extends TestCase
{
    #[Test]
    public function validRowPassesValidation(): void
    {
        $validator = new TeacherImportRowValidator();

        $row = $this->createRow([
            TeacherImportField::LAST_NAME->value => 'Dupont',
            TeacherImportField::FIRST_NAME->value => 'Jean',
            TeacherImportField::EMAIL->value => 'jean.dupont@ecole.fr',
        ]);

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

        self::assertTrue($validated->estValide());
    }

    #[Test]
    public function missingLastNameCreatesError(): void
    {
        $validator = new TeacherImportRowValidator();

        $row = $this->createRow([
            TeacherImportField::LAST_NAME->value => '',
            TeacherImportField::FIRST_NAME->value => 'Jean',
            TeacherImportField::EMAIL->value => 'jean@ecole.fr',
        ]);

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

        self::assertFalse($validated->estValide());
        self::assertCount(1, $validated->errors);
        self::assertSame('lastName', $validated->errors[0]->column);
    }

    #[Test]
    public function missingFirstNameCreatesError(): void
    {
        $validator = new TeacherImportRowValidator();

        $row = $this->createRow([
            TeacherImportField::LAST_NAME->value => 'Dupont',
            TeacherImportField::FIRST_NAME->value => '',
            TeacherImportField::EMAIL->value => 'jean@ecole.fr',
        ]);

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

        self::assertFalse($validated->estValide());
        self::assertCount(1, $validated->errors);
        self::assertSame('firstName', $validated->errors[0]->column);
    }

    #[Test]
    public function missingEmailCreatesError(): void
    {
        $validator = new TeacherImportRowValidator();

        $row = $this->createRow([
            TeacherImportField::LAST_NAME->value => 'Dupont',
            TeacherImportField::FIRST_NAME->value => 'Jean',
            TeacherImportField::EMAIL->value => '',
        ]);

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

        self::assertFalse($validated->estValide());
        self::assertCount(1, $validated->errors);
        self::assertSame('email', $validated->errors[0]->column);
    }

    #[Test]
    public function invalidEmailCreatesError(): void
    {
        $validator = new TeacherImportRowValidator();

        $row = $this->createRow([
            TeacherImportField::LAST_NAME->value => 'Dupont',
            TeacherImportField::FIRST_NAME->value => 'Jean',
            TeacherImportField::EMAIL->value => 'not-an-email',
        ]);

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

        self::assertFalse($validated->estValide());
        self::assertSame('email', $validated->errors[0]->column);
    }

    #[Test]
    public function unknownSubjectCreatesErrorWhenExistingSubjectsProvided(): void
    {
        $validator = new TeacherImportRowValidator(
            existingSubjectNames: ['Mathématiques', 'Physique'],
        );

        $row = $this->createRow([
            TeacherImportField::LAST_NAME->value => 'Dupont',
            TeacherImportField::FIRST_NAME->value => 'Jean',
            TeacherImportField::EMAIL->value => 'jean@ecole.fr',
            TeacherImportField::SUBJECTS->value => 'Mathématiques, Chimie',
        ]);

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

        self::assertFalse($validated->estValide());
        self::assertSame('subjects', $validated->errors[0]->column);
        self::assertStringContainsString('Chimie', $validated->errors[0]->message);
    }

    #[Test]
    public function knownSubjectsPassValidation(): void
    {
        $validator = new TeacherImportRowValidator(
            existingSubjectNames: ['Mathématiques', 'Physique'],
        );

        $row = $this->createRow([
            TeacherImportField::LAST_NAME->value => 'Dupont',
            TeacherImportField::FIRST_NAME->value => 'Jean',
            TeacherImportField::EMAIL->value => 'jean@ecole.fr',
            TeacherImportField::SUBJECTS->value => 'Mathématiques, Physique',
        ]);

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

        self::assertTrue($validated->estValide());
    }

    #[Test]
    public function unknownClassCreatesErrorWhenExistingClassesProvided(): void
    {
        $validator = new TeacherImportRowValidator(
            existingClassNames: ['6A', '6B', '5A'],
        );

        $row = $this->createRow([
            TeacherImportField::LAST_NAME->value => 'Dupont',
            TeacherImportField::FIRST_NAME->value => 'Jean',
            TeacherImportField::EMAIL->value => 'jean@ecole.fr',
            TeacherImportField::CLASSES->value => '6A, 4C',
        ]);

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

        self::assertFalse($validated->estValide());
        self::assertSame('classes', $validated->errors[0]->column);
        self::assertStringContainsString('4C', $validated->errors[0]->message);
    }

    #[Test]
    public function emptySubjectsPassValidation(): void
    {
        $validator = new TeacherImportRowValidator(
            existingSubjectNames: ['Mathématiques'],
        );

        $row = $this->createRow([
            TeacherImportField::LAST_NAME->value => 'Dupont',
            TeacherImportField::FIRST_NAME->value => 'Jean',
            TeacherImportField::EMAIL->value => 'jean@ecole.fr',
            TeacherImportField::SUBJECTS->value => '',
        ]);

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

        self::assertTrue($validated->estValide());
    }

    #[Test]
    public function validerToutValidatesAllRows(): void
    {
        $validator = new TeacherImportRowValidator();

        $rows = [
            $this->createRow([
                TeacherImportField::LAST_NAME->value => 'Dupont',
                TeacherImportField::FIRST_NAME->value => 'Jean',
                TeacherImportField::EMAIL->value => 'jean@ecole.fr',
            ]),
            $this->createRow([
                TeacherImportField::LAST_NAME->value => '',
                TeacherImportField::FIRST_NAME->value => 'Marie',
                TeacherImportField::EMAIL->value => 'marie@ecole.fr',
            ]),
        ];

        $validated = $validator->validerTout($rows);

        self::assertCount(2, $validated);
        self::assertTrue($validated[0]->estValide());
        self::assertFalse($validated[1]->estValide());
    }

    #[Test]
    public function subjectsNotCheckedWhenNoExistingSubjectsProvided(): void
    {
        $validator = new TeacherImportRowValidator();

        $row = $this->createRow([
            TeacherImportField::LAST_NAME->value => 'Dupont',
            TeacherImportField::FIRST_NAME->value => 'Jean',
            TeacherImportField::EMAIL->value => 'jean@ecole.fr',
            TeacherImportField::SUBJECTS->value => 'N\'importe quoi',
        ]);

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

        self::assertTrue($validated->estValide());
    }

    /**
     * @param array<string, string> $mappedData
     */
    private function createRow(array $mappedData, int $line = 1): ImportRow
    {
        return new ImportRow($line, $mappedData, $mappedData);
    }
}
