<?php

namespace Tests\Unit\Enums;

use App\Enums\LogLevelEnum;
use Tests\TestCase;

class LogLevelEnumTest extends TestCase
{
    public function test_enum_cases_have_correct_values(): void
    {
        $this->assertEquals('debug', LogLevelEnum::DEBUG->value);
        $this->assertEquals('info', LogLevelEnum::INFO->value);
        $this->assertEquals('warning', LogLevelEnum::WARNING->value);
        $this->assertEquals('error', LogLevelEnum::ERROR->value);
        $this->assertEquals('critical', LogLevelEnum::CRITICAL->value);
    }

    public function test_to_array_returns_all_enum_values(): void
    {
        $expected = ['debug', 'info', 'warning', 'error', 'critical'];
        $actual = LogLevelEnum::toArray();

        $this->assertEquals($expected, $actual);
        $this->assertCount(5, $actual);
    }

    public function test_enum_cases_exist(): void
    {
        $cases = LogLevelEnum::cases();

        $this->assertCount(5, $cases);
        $this->assertContains(LogLevelEnum::DEBUG, $cases);
        $this->assertContains(LogLevelEnum::INFO, $cases);
        $this->assertContains(LogLevelEnum::WARNING, $cases);
        $this->assertContains(LogLevelEnum::ERROR, $cases);
        $this->assertContains(LogLevelEnum::CRITICAL, $cases);
    }

    public function test_enum_names_are_correct(): void
    {
        $this->assertEquals('DEBUG', LogLevelEnum::DEBUG->name);
        $this->assertEquals('INFO', LogLevelEnum::INFO->name);
        $this->assertEquals('WARNING', LogLevelEnum::WARNING->name);
        $this->assertEquals('ERROR', LogLevelEnum::ERROR->name);
        $this->assertEquals('CRITICAL', LogLevelEnum::CRITICAL->name);
    }

    public function test_can_create_enum_from_string(): void
    {
        $this->assertEquals(LogLevelEnum::DEBUG, LogLevelEnum::from('debug'));
        $this->assertEquals(LogLevelEnum::INFO, LogLevelEnum::from('info'));
        $this->assertEquals(LogLevelEnum::WARNING, LogLevelEnum::from('warning'));
        $this->assertEquals(LogLevelEnum::ERROR, LogLevelEnum::from('error'));
        $this->assertEquals(LogLevelEnum::CRITICAL, LogLevelEnum::from('critical'));
    }

    public function test_try_from_with_valid_values(): void
    {
        $this->assertEquals(LogLevelEnum::DEBUG, LogLevelEnum::tryFrom('debug'));
        $this->assertEquals(LogLevelEnum::INFO, LogLevelEnum::tryFrom('info'));
        $this->assertEquals(LogLevelEnum::WARNING, LogLevelEnum::tryFrom('warning'));
        $this->assertEquals(LogLevelEnum::ERROR, LogLevelEnum::tryFrom('error'));
        $this->assertEquals(LogLevelEnum::CRITICAL, LogLevelEnum::tryFrom('critical'));
    }

    public function test_try_from_with_invalid_value_returns_null(): void
    {
        $this->assertNull(LogLevelEnum::tryFrom('invalid'));
        $this->assertNull(LogLevelEnum::tryFrom(''));
        $this->assertNull(LogLevelEnum::tryFrom('CRITICAL')); // case sensitive
    }

    public function test_from_throws_exception_for_invalid_value(): void
    {
        $this->expectException(\ValueError::class);
        LogLevelEnum::from('invalid');
    }

    public function test_enum_can_be_compared(): void
    {
        $debug1 = LogLevelEnum::DEBUG;
        $debug2 = LogLevelEnum::DEBUG;
        $info = LogLevelEnum::INFO;

        $this->assertTrue($debug1 === $debug2);
        $this->assertFalse($debug1 === $info);
    }

    public function test_enum_can_be_used_in_match_expression(): void
    {
        $getMessage = function (LogLevelEnum $level): string {
            return match ($level) {
                LogLevelEnum::DEBUG => 'Debug message',
                LogLevelEnum::INFO => 'Info message',
                LogLevelEnum::WARNING => 'Warning message',
                LogLevelEnum::ERROR => 'Error message',
                LogLevelEnum::CRITICAL => 'Critical message',
            };
        };

        $this->assertEquals('Debug message', $getMessage(LogLevelEnum::DEBUG));
        $this->assertEquals('Info message', $getMessage(LogLevelEnum::INFO));
        $this->assertEquals('Warning message', $getMessage(LogLevelEnum::WARNING));
        $this->assertEquals('Error message', $getMessage(LogLevelEnum::ERROR));
        $this->assertEquals('Critical message', $getMessage(LogLevelEnum::CRITICAL));
    }
}
