<?php

declare(strict_types=1);

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

use App\Administration\Domain\Exception\SubjectNameInvalideException;
use App\Administration\Domain\Model\Subject\SubjectName;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class SubjectNameTest extends TestCase
{
    #[Test]
    public function constructWithValidName(): void
    {
        $name = new SubjectName('Mathématiques');

        self::assertSame('Mathématiques', $name->value);
    }

    #[Test]
    public function constructTrimsWhitespace(): void
    {
        $name = new SubjectName('  Mathématiques  ');

        self::assertSame('Mathématiques', $name->value);
    }

    #[Test]
    public function constructWithMinimumLength(): void
    {
        $name = new SubjectName('FR');

        self::assertSame('FR', $name->value);
    }

    #[Test]
    public function constructWithMaximumLength(): void
    {
        $longName = str_repeat('M', 100);
        $name = new SubjectName($longName);

        self::assertSame($longName, $name->value);
    }

    #[Test]
    #[DataProvider('invalidNamesProvider')]
    public function constructThrowsExceptionForInvalidName(string $invalidName): void
    {
        $this->expectException(SubjectNameInvalideException::class);

        new SubjectName($invalidName);
    }

    /**
     * @return iterable<string, array{string}>
     */
    public static function invalidNamesProvider(): iterable
    {
        yield 'empty string' => [''];
        yield 'single character' => ['M'];
        yield 'whitespace only' => ['   '];
        yield 'too long' => [str_repeat('M', 101)];
    }

    #[Test]
    public function equalsReturnsTrueForSameValue(): void
    {
        $name1 = new SubjectName('Mathématiques');
        $name2 = new SubjectName('Mathématiques');

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

    #[Test]
    public function equalsReturnsFalseForDifferentValue(): void
    {
        $name1 = new SubjectName('Mathématiques');
        $name2 = new SubjectName('Français');

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

    #[Test]
    public function toStringReturnsValue(): void
    {
        $name = new SubjectName('Mathématiques');

        self::assertSame('Mathématiques', (string) $name);
    }
}
