<?php

namespace Tests\Unit\Models;

use App\Models\Feed;
use App\Models\Language;
use App\Models\PlatformChannel;
use App\Models\PlatformInstance;
use Carbon\Carbon;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class LanguageTest extends TestCase
{
    use RefreshDatabase;

    public function test_fillable_fields(): void
    {
        $fillableFields = ['short_code', 'name', 'native_name', 'is_active'];
        $language = new Language;

        $this->assertEquals($fillableFields, $language->getFillable());
    }

    public function test_table_name(): void
    {
        $language = new Language;

        $this->assertEquals('languages', $language->getTable());
    }

    public function test_casts_is_active_to_boolean(): void
    {
        $language = Language::factory()->create(['is_active' => '1']);

        $this->assertIsBool($language->is_active);
        $this->assertTrue($language->is_active);

        $language->update(['is_active' => '0']);
        $language->refresh();

        $this->assertIsBool($language->is_active);
        $this->assertFalse($language->is_active);
    }

    public function test_belongs_to_many_platform_instances_relationship(): void
    {
        $language = Language::factory()->create();
        $instance1 = PlatformInstance::factory()->create();
        $instance2 = PlatformInstance::factory()->create();

        // Attach with required platform_language_id
        $language->platformInstances()->attach([
            $instance1->id => ['platform_language_id' => 1],
            $instance2->id => ['platform_language_id' => 2],
        ]);

        $instances = $language->platformInstances;

        $this->assertCount(2, $instances);
        $this->assertTrue($instances->contains('id', $instance1->id));
        $this->assertTrue($instances->contains('id', $instance2->id));
    }

    public function test_has_many_platform_channels_relationship(): void
    {
        $language = Language::factory()->create();

        $channel1 = PlatformChannel::factory()->create(['language_id' => $language->id]);
        $channel2 = PlatformChannel::factory()->create(['language_id' => $language->id]);

        // Create channel for different language
        $otherLanguage = Language::factory()->create();
        PlatformChannel::factory()->create(['language_id' => $otherLanguage->id]);

        $channels = $language->platformChannels;

        $this->assertCount(2, $channels);
        $this->assertTrue($channels->contains('id', $channel1->id));
        $this->assertTrue($channels->contains('id', $channel2->id));
        $this->assertInstanceOf(PlatformChannel::class, $channels->first());
    }

    public function test_has_many_feeds_relationship(): void
    {
        $language = Language::factory()->create();

        $feed1 = Feed::factory()->create(['language_id' => $language->id]);
        $feed2 = Feed::factory()->create(['language_id' => $language->id]);

        // Create feed for different language
        $otherLanguage = Language::factory()->create();
        Feed::factory()->create(['language_id' => $otherLanguage->id]);

        $feeds = $language->feeds;

        $this->assertCount(2, $feeds);
        $this->assertTrue($feeds->contains('id', $feed1->id));
        $this->assertTrue($feeds->contains('id', $feed2->id));
        $this->assertInstanceOf(Feed::class, $feeds->first());
    }

    public function test_language_creation_with_factory(): void
    {
        $language = Language::factory()->create();

        $this->assertInstanceOf(Language::class, $language);
        $this->assertIsString($language->short_code);
        $this->assertIsString($language->name);
        $this->assertTrue($language->is_active);
    }

    public function test_language_creation_with_explicit_values(): void
    {
        $language = Language::create([
            'short_code' => 'fr',
            'name' => 'French',
            'native_name' => 'Français',
            'is_active' => false,
        ]);

        $this->assertEquals('fr', $language->short_code);
        $this->assertEquals('French', $language->name);
        $this->assertEquals('Français', $language->native_name);
        $this->assertFalse($language->is_active);
    }

    public function test_language_factory_states(): void
    {
        $inactiveLanguage = Language::factory()->inactive()->create();
        $this->assertFalse($inactiveLanguage->is_active);

        $englishLanguage = Language::factory()->english()->create();
        $this->assertEquals('en', $englishLanguage->short_code);
        $this->assertEquals('English', $englishLanguage->name);
        $this->assertEquals('English', $englishLanguage->native_name);
    }

    public function test_language_update(): void
    {
        $language = Language::factory()->create([
            'name' => 'Original Name',
            'is_active' => true,
        ]);

        $language->update([
            'name' => 'Updated Name',
            'is_active' => false,
        ]);

        $language->refresh();

        $this->assertEquals('Updated Name', $language->name);
        $this->assertFalse($language->is_active);
    }

    public function test_language_deletion(): void
    {
        $language = Language::factory()->create();
        $languageId = $language->id;

        $language->delete();

        $this->assertDatabaseMissing('languages', ['id' => $languageId]);
    }

    public function test_language_can_have_null_native_name(): void
    {
        $language = Language::factory()->create(['native_name' => null]);

        $this->assertNull($language->native_name);
    }

    public function test_language_can_have_empty_native_name(): void
    {
        $language = Language::factory()->create(['native_name' => '']);

        $this->assertEquals('', $language->native_name);
    }

    public function test_language_short_code_variations(): void
    {
        $shortCodes = ['en', 'fr', 'es', 'de', 'zh', 'pt', 'nl', 'it'];

        foreach ($shortCodes as $code) {
            $language = Language::factory()->create(['short_code' => $code]);
            $this->assertEquals($code, $language->short_code);
        }
    }

    public function test_language_timestamps(): void
    {
        $language = Language::factory()->create();

        $this->assertNotNull($language->created_at);
        $this->assertNotNull($language->updated_at);
        $this->assertInstanceOf(Carbon::class, $language->created_at);
        $this->assertInstanceOf(Carbon::class, $language->updated_at);
    }

    public function test_language_can_have_multiple_platform_instances(): void
    {
        $language = Language::factory()->create();
        $instance1 = PlatformInstance::factory()->create();
        $instance2 = PlatformInstance::factory()->create();
        $instance3 = PlatformInstance::factory()->create();

        // Attach with required platform_language_id values
        $language->platformInstances()->attach([
            $instance1->id => ['platform_language_id' => 1],
            $instance2->id => ['platform_language_id' => 2],
            $instance3->id => ['platform_language_id' => 3],
        ]);

        $instances = $language->platformInstances;

        $this->assertCount(3, $instances);
        $this->assertTrue($instances->contains('id', $instance1->id));
        $this->assertTrue($instances->contains('id', $instance2->id));
        $this->assertTrue($instances->contains('id', $instance3->id));
    }

    public function test_language_platform_instances_relationship_is_empty_by_default(): void
    {
        $language = Language::factory()->create();

        $this->assertCount(0, $language->platformInstances);
    }

    public function test_language_platform_channels_relationship_is_empty_by_default(): void
    {
        $language = Language::factory()->create();

        $this->assertCount(0, $language->platformChannels);
    }

    public function test_language_feeds_relationship_is_empty_by_default(): void
    {
        $language = Language::factory()->create();

        $this->assertCount(0, $language->feeds);
    }

    public function test_multiple_languages_with_same_name_different_regions(): void
    {
        $englishUS = Language::factory()->create([
            'short_code' => 'en-US',
            'name' => 'English (United States)',
            'native_name' => 'English',
        ]);

        $englishGB = Language::factory()->create([
            'short_code' => 'en-GB',
            'name' => 'English (United Kingdom)',
            'native_name' => 'English',
        ]);

        $this->assertEquals('English', $englishUS->native_name);
        $this->assertEquals('English', $englishGB->native_name);
        $this->assertNotEquals($englishUS->short_code, $englishGB->short_code);
        $this->assertNotEquals($englishUS->name, $englishGB->name);
    }

    public function test_language_with_complex_native_name(): void
    {
        $complexLanguages = [
            ['short_code' => 'zh-CN', 'name' => 'Chinese (Simplified)', 'native_name' => '简体中文'],
            ['short_code' => 'zh-TW', 'name' => 'Chinese (Traditional)', 'native_name' => '繁體中文'],
            ['short_code' => 'ar', 'name' => 'Arabic', 'native_name' => 'العربية'],
            ['short_code' => 'ru', 'name' => 'Russian', 'native_name' => 'Русский'],
            ['short_code' => 'ja', 'name' => 'Japanese', 'native_name' => '日本語'],
        ];

        foreach ($complexLanguages as $langData) {
            $language = Language::factory()->create($langData);

            $this->assertEquals($langData['short_code'], $language->short_code);
            $this->assertEquals($langData['name'], $language->name);
            $this->assertEquals($langData['native_name'], $language->native_name);
        }
    }

    public function test_language_active_and_inactive_states(): void
    {
        $activeLanguage = Language::factory()->create(['is_active' => true]);
        $inactiveLanguage = Language::factory()->create(['is_active' => false]);

        $this->assertTrue($activeLanguage->is_active);
        $this->assertFalse($inactiveLanguage->is_active);
    }

    public function test_language_relationships_maintain_referential_integrity(): void
    {
        $language = Language::factory()->create();

        // Create related models
        $instance = PlatformInstance::factory()->create();
        $channel = PlatformChannel::factory()->create(['language_id' => $language->id]);
        $feed = Feed::factory()->create(['language_id' => $language->id]);

        // Attach instance
        $language->platformInstances()->attach($instance->id, [
            'platform_language_id' => 1,
            'is_default' => true,
        ]);

        // Verify all relationships work
        $this->assertCount(1, $language->platformInstances);
        $this->assertCount(1, $language->platformChannels);
        $this->assertCount(1, $language->feeds);

        $this->assertEquals($language->id, $channel->language_id);
        $this->assertEquals($language->id, $feed->language_id);
    }

    public function test_language_factory_unique_constraints(): void
    {
        // The factory should generate unique short codes
        $language1 = Language::factory()->create();
        $language2 = Language::factory()->create();

        $this->assertNotEquals($language1->short_code, $language2->short_code);
        $this->assertNotEquals($language1->name, $language2->name);
    }
}
