<?php

declare(strict_types=1);

namespace App\Tests\Unit\Administration\Domain\Model\SchoolClass;

use App\Administration\Domain\Exception\ClassNameInvalideException;
use App\Administration\Domain\Model\SchoolClass\ClassName;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class ClassNameTest extends TestCase
{
    #[Test]
    public function constructWithValidName(): void
    {
        $name = new ClassName('6ème A');

        self::assertSame('6ème A', $name->value);
        self::assertSame('6ème A', (string) $name);
    }

    #[Test]
    public function constructTrimsWhitespace(): void
    {
        $name = new ClassName('  6ème A  ');

        self::assertSame('6ème A', $name->value);
    }

    #[Test]
    #[DataProvider('validNamesProvider')]
    public function constructAcceptsValidNames(string $value): void
    {
        $name = new ClassName($value);

        self::assertNotEmpty($name->value);
    }

    /**
     * @return array<string, array{string}>
     */
    public static function validNamesProvider(): array
    {
        return [
            'minimum length' => ['AB'],
            'typical class name' => ['6ème A'],
            'longer name' => ['Classe préparatoire aux grandes écoles'],
            'with numbers' => ['CM1-2'],
            'maximum length' => [str_repeat('A', 50)],
        ];
    }

    #[Test]
    #[DataProvider('invalidNamesProvider')]
    public function constructRejectsInvalidNames(string $value): void
    {
        $this->expectException(ClassNameInvalideException::class);

        new ClassName($value);
    }

    /**
     * @return array<string, array{string}>
     */
    public static function invalidNamesProvider(): array
    {
        return [
            'empty string' => [''],
            'single character' => ['A'],
            'only whitespace' => ['   '],
            'one char after trim' => ['  A  '],
            'too long' => [str_repeat('A', 51)],
        ];
    }

    #[Test]
    public function equalsReturnsTrueForSameValue(): void
    {
        $name1 = new ClassName('6ème A');
        $name2 = new ClassName('6ème A');

        self::assertTrue($name1->equals($name2));
    }

    #[Test]
    public function equalsReturnsFalseForDifferentValue(): void
    {
        $name1 = new ClassName('6ème A');
        $name2 = new ClassName('6ème B');

        self::assertFalse($name1->equals($name2));
    }

    #[Test]
    public function equalsIsCaseSensitive(): void
    {
        $name1 = new ClassName('Classe A');
        $name2 = new ClassName('classe A');

        self::assertFalse($name1->equals($name2));
    }
}
