<?php

declare(strict_types=1);

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

use App\Administration\Domain\Exception\SubjectColorInvalideException;
use App\Administration\Domain\Model\Subject\SubjectColor;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;

final class SubjectColorTest extends TestCase
{
    #[Test]
    public function constructWithValidColor(): void
    {
        $color = new SubjectColor('#3B82F6');

        self::assertSame('#3B82F6', $color->value);
    }

    #[Test]
    public function constructNormalizesToUppercase(): void
    {
        $color = new SubjectColor('#3b82f6');

        self::assertSame('#3B82F6', $color->value);
    }

    #[Test]
    public function constructTrimsWhitespace(): void
    {
        $color = new SubjectColor('  #3B82F6  ');

        self::assertSame('#3B82F6', $color->value);
    }

    #[Test]
    #[DataProvider('validColorsProvider')]
    public function constructWithValidColors(string $input, string $expected): void
    {
        $color = new SubjectColor($input);

        self::assertSame($expected, $color->value);
    }

    /**
     * @return iterable<string, array{string, string}>
     */
    public static function validColorsProvider(): iterable
    {
        yield 'blue' => ['#3B82F6', '#3B82F6'];
        yield 'red' => ['#EF4444', '#EF4444'];
        yield 'green' => ['#10B981', '#10B981'];
        yield 'orange' => ['#F59E0B', '#F59E0B'];
        yield 'black' => ['#000000', '#000000'];
        yield 'white' => ['#FFFFFF', '#FFFFFF'];
        yield 'lowercase' => ['#aabbcc', '#AABBCC'];
    }

    #[Test]
    #[DataProvider('invalidColorsProvider')]
    public function constructThrowsExceptionForInvalidColor(string $invalidColor): void
    {
        $this->expectException(SubjectColorInvalideException::class);

        new SubjectColor($invalidColor);
    }

    /**
     * @return iterable<string, array{string}>
     */
    public static function invalidColorsProvider(): iterable
    {
        yield 'empty string' => [''];
        yield 'no hash' => ['3B82F6'];
        yield 'short format' => ['#FFF'];
        yield 'too short' => ['#3B82F'];
        yield 'too long' => ['#3B82F6F'];
        yield 'invalid characters' => ['#GGGGGG'];
        yield 'rgb format' => ['rgb(59,130,246)'];
        yield 'named color' => ['blue'];
    }

    #[Test]
    public function equalsReturnsTrueForSameValue(): void
    {
        $color1 = new SubjectColor('#3B82F6');
        $color2 = new SubjectColor('#3B82F6');

        self::assertTrue($color1->equals($color2));
    }

    #[Test]
    public function equalsReturnsTrueForDifferentCase(): void
    {
        $color1 = new SubjectColor('#3B82F6');
        $color2 = new SubjectColor('#3b82f6');

        self::assertTrue($color1->equals($color2));
    }

    #[Test]
    public function equalsReturnsFalseForDifferentValue(): void
    {
        $color1 = new SubjectColor('#3B82F6');
        $color2 = new SubjectColor('#EF4444');

        self::assertFalse($color1->equals($color2));
    }

    #[Test]
    public function toStringReturnsValue(): void
    {
        $color = new SubjectColor('#3B82F6');

        self::assertSame('#3B82F6', (string) $color);
    }
}
