<?php

declare(strict_types=1);

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

use App\Administration\Domain\Exception\SubjectCodeInvalideException;
use App\Administration\Domain\Model\Subject\SubjectCode;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class SubjectCodeTest extends TestCase
{
    #[Test]
    public function constructWithValidCode(): void
    {
        $code = new SubjectCode('MATH');

        self::assertSame('MATH', $code->value);
    }

    #[Test]
    public function constructNormalizesToUppercase(): void
    {
        $code = new SubjectCode('math');

        self::assertSame('MATH', $code->value);
    }

    #[Test]
    public function constructTrimsWhitespace(): void
    {
        $code = new SubjectCode('  MATH  ');

        self::assertSame('MATH', $code->value);
    }

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

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

    #[Test]
    public function constructWithMaximumLength(): void
    {
        $code = new SubjectCode('HISTGEO123');

        self::assertSame('HISTGEO123', $code->value);
    }

    #[Test]
    public function constructWithDigits(): void
    {
        $code = new SubjectCode('EPS1');

        self::assertSame('EPS1', $code->value);
    }

    #[Test]
    #[DataProvider('invalidCodesProvider')]
    public function constructThrowsExceptionForInvalidCode(string $invalidCode): void
    {
        $this->expectException(SubjectCodeInvalideException::class);

        new SubjectCode($invalidCode);
    }

    /**
     * @return iterable<string, array{string}>
     */
    public static function invalidCodesProvider(): iterable
    {
        yield 'empty string' => [''];
        yield 'single character' => ['M'];
        yield 'whitespace only' => ['   '];
        yield 'too long' => ['MATHEMATICS'];  // 11 chars
        yield 'with special characters' => ['MATH-1'];
        yield 'with spaces' => ['MA TH'];
        yield 'lowercase with special' => ['math!'];
    }

    #[Test]
    public function equalsReturnsTrueForSameValue(): void
    {
        $code1 = new SubjectCode('MATH');
        $code2 = new SubjectCode('MATH');

        self::assertTrue($code1->equals($code2));
    }

    #[Test]
    public function equalsReturnsTrueForDifferentCase(): void
    {
        $code1 = new SubjectCode('MATH');
        $code2 = new SubjectCode('math');

        self::assertTrue($code1->equals($code2));
    }

    #[Test]
    public function equalsReturnsFalseForDifferentValue(): void
    {
        $code1 = new SubjectCode('MATH');
        $code2 = new SubjectCode('FR');

        self::assertFalse($code1->equals($code2));
    }

    #[Test]
    public function toStringReturnsValue(): void
    {
        $code = new SubjectCode('MATH');

        self::assertSame('MATH', (string) $code);
    }
}
