<?php

namespace Tests\Unit\Exceptions;

use App\Exceptions\RoutingException;
use App\Exceptions\RoutingMismatchException;
use App\Models\Feed;
use App\Models\Language;
use App\Models\PlatformChannel;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class RoutingMismatchExceptionTest extends TestCase
{
    use RefreshDatabase;

    public function test_exception_constructs_with_correct_message(): void
    {
        // Arrange
        $englishLang = Language::factory()->create(['short_code' => 'en', 'name' => 'English']);
        $frenchLang = Language::factory()->create(['short_code' => 'fr', 'name' => 'French']);

        $feed = new Feed(['name' => 'Test Feed']);
        $feed->setRelation('language', $englishLang);

        $channel = new PlatformChannel(['name' => 'Test Channel']);
        $channel->setRelation('language', $frenchLang);

        // Act
        $exception = new RoutingMismatchException($feed, $channel);

        // Assert
        $message = $exception->getMessage();
        $this->assertStringContainsString('Language mismatch:', $message);
        $this->assertStringContainsString('Test Feed', $message);
        $this->assertStringContainsString('Test Channel', $message);
        $this->assertStringContainsString('Feed and channel languages must match', $message);
    }

    public function test_exception_extends_routing_exception(): void
    {
        // Arrange
        $englishLang = Language::factory()->create(['short_code' => 'en']);
        $frenchLang = Language::factory()->create(['short_code' => 'fr']);

        $feed = new Feed(['name' => 'Test Feed']);
        $feed->setRelation('language', $englishLang);

        $channel = new PlatformChannel(['name' => 'Test Channel']);
        $channel->setRelation('language', $frenchLang);

        // Act
        $exception = new RoutingMismatchException($feed, $channel);

        // Assert
        $this->assertInstanceOf(RoutingException::class, $exception);
    }

    public function test_exception_with_different_languages(): void
    {
        // Arrange
        $dutchLang = Language::factory()->create(['short_code' => 'nl', 'name' => 'Dutch']);
        $germanLang = Language::factory()->create(['short_code' => 'de', 'name' => 'German']);

        $feed = new Feed(['name' => 'Dutch News']);
        $feed->setRelation('language', $dutchLang);

        $channel = new PlatformChannel(['name' => 'German Channel']);
        $channel->setRelation('language', $germanLang);

        // Act
        $exception = new RoutingMismatchException($feed, $channel);

        // Assert
        $message = $exception->getMessage();
        $this->assertStringContainsString('Dutch News', $message);
        $this->assertStringContainsString('German Channel', $message);
        $this->assertStringContainsString('Language mismatch', $message);
    }

    public function test_exception_message_contains_all_required_elements(): void
    {
        // Arrange
        $frenchLang = Language::factory()->create(['short_code' => 'fr', 'name' => 'French']);
        $spanishLang = Language::factory()->create(['short_code' => 'es', 'name' => 'Spanish']);

        $feed = new Feed(['name' => 'French Feed']);
        $feed->setRelation('language', $frenchLang);

        $channel = new PlatformChannel(['name' => 'Spanish Channel']);
        $channel->setRelation('language', $spanishLang);

        // Act
        $exception = new RoutingMismatchException($feed, $channel);
        $message = $exception->getMessage();

        // Assert
        $this->assertStringContainsString('Language mismatch:', $message);
        $this->assertStringContainsString('French Feed', $message);
        $this->assertStringContainsString('Spanish Channel', $message);
        $this->assertStringContainsString('Feed and channel languages must match', $message);
    }

    public function test_exception_with_null_languages(): void
    {
        // Arrange
        $feed = new Feed(['name' => 'No Lang Feed']);
        $feed->setRelation('language', null);

        $channel = new PlatformChannel(['name' => 'No Lang Channel']);
        $channel->setRelation('language', null);

        // Act
        $exception = new RoutingMismatchException($feed, $channel);

        // Assert
        $message = $exception->getMessage();
        $this->assertStringContainsString('No Lang Feed', $message);
        $this->assertStringContainsString('No Lang Channel', $message);
        $this->assertIsString($message);
    }

    public function test_exception_with_special_characters_in_names(): void
    {
        // Arrange
        $englishLang = Language::factory()->create(['short_code' => 'en']);
        $frenchLang = Language::factory()->create(['short_code' => 'fr']);

        $feed = new Feed(['name' => 'Feed with "quotes" & symbols']);
        $feed->setRelation('language', $englishLang);

        $channel = new PlatformChannel(['name' => 'Channel with <tags>']);
        $channel->setRelation('language', $frenchLang);

        // Act
        $exception = new RoutingMismatchException($feed, $channel);

        // Assert
        $message = $exception->getMessage();
        $this->assertStringContainsString('Feed with "quotes" & symbols', $message);
        $this->assertStringContainsString('Channel with <tags>', $message);
        $this->assertIsString($message);
    }

    public function test_exception_is_throwable(): void
    {
        // Arrange
        $englishLang = Language::factory()->create(['short_code' => 'en']);
        $frenchLang = Language::factory()->create(['short_code' => 'fr']);

        $feed = new Feed(['name' => 'Test Feed']);
        $feed->setRelation('language', $englishLang);

        $channel = new PlatformChannel(['name' => 'Test Channel']);
        $channel->setRelation('language', $frenchLang);

        // Act & Assert
        $this->expectException(RoutingMismatchException::class);
        $this->expectExceptionMessage('Language mismatch');

        throw new RoutingMismatchException($feed, $channel);
    }
}
