<?php

namespace Tests\Unit\Models;

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

class PlatformInstanceTest extends TestCase
{
    use RefreshDatabase;

    public function test_fillable_fields(): void
    {
        $fillableFields = ['platform', 'url', 'name', 'description', 'is_active'];
        $instance = new PlatformInstance;

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

    public function test_table_name(): void
    {
        $instance = new PlatformInstance;

        $this->assertEquals('platform_instances', $instance->getTable());
    }

    public function test_casts_platform_to_enum(): void
    {
        $instance = PlatformInstance::factory()->create(['platform' => PlatformEnum::LEMMY]);

        $this->assertInstanceOf(PlatformEnum::class, $instance->platform);
        $this->assertEquals(PlatformEnum::LEMMY, $instance->platform);
        $this->assertEquals('lemmy', $instance->platform->value);
    }

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

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

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

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

    public function test_has_many_channels_relationship(): void
    {
        $instance = PlatformInstance::factory()->create();

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

        // Create channel for different instance
        $otherInstance = PlatformInstance::factory()->create();
        PlatformChannel::factory()->create(['platform_instance_id' => $otherInstance->id]);

        $channels = $instance->channels;

        $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_belongs_to_many_languages_relationship(): void
    {
        $instance = PlatformInstance::factory()->create();
        $language1 = Language::factory()->create();
        $language2 = Language::factory()->create();

        // Attach languages with pivot data
        $instance->languages()->attach($language1->id, [
            'platform_language_id' => 1,
            'is_default' => true,
        ]);

        $instance->languages()->attach($language2->id, [
            'platform_language_id' => 2,
            'is_default' => false,
        ]);

        $languages = $instance->languages;

        $this->assertCount(2, $languages);
        $this->assertTrue($languages->contains('id', $language1->id));
        $this->assertTrue($languages->contains('id', $language2->id));

        // Test pivot data
        $language1FromRelation = $languages->find($language1->id);
        $this->assertEquals(1, $language1FromRelation->pivot->platform_language_id);
        $this->assertEquals(1, $language1FromRelation->pivot->is_default);

        $language2FromRelation = $languages->find($language2->id);
        $this->assertEquals(2, $language2FromRelation->pivot->platform_language_id);
        $this->assertEquals(0, $language2FromRelation->pivot->is_default);
    }

    public function test_find_by_url_static_method(): void
    {
        $url = 'https://lemmy.world';

        $instance1 = PlatformInstance::factory()->create([
            'platform' => PlatformEnum::LEMMY,
            'url' => $url,
        ]);

        // Create instance with different URL
        PlatformInstance::factory()->create([
            'platform' => PlatformEnum::LEMMY,
            'url' => 'https://lemmy.ml',
        ]);

        $foundInstance = PlatformInstance::findByUrl(PlatformEnum::LEMMY, $url);

        $this->assertNotNull($foundInstance);
        $this->assertEquals($instance1->id, $foundInstance->id);
        $this->assertEquals($url, $foundInstance->url);
        $this->assertEquals(PlatformEnum::LEMMY, $foundInstance->platform);
    }

    public function test_find_by_url_returns_null_when_not_found(): void
    {
        $foundInstance = PlatformInstance::findByUrl(PlatformEnum::LEMMY, 'https://nonexistent.lemmy');

        $this->assertNull($foundInstance);
    }

    public function test_find_by_url_filters_by_platform(): void
    {
        $url = 'https://example.com';

        // Create instance with same URL but different platform won't be found
        PlatformInstance::factory()->create([
            'platform' => PlatformEnum::LEMMY,
            'url' => $url,
        ]);

        // Since we only have LEMMY in the enum, this test demonstrates the filtering logic
        $foundInstance = PlatformInstance::findByUrl(PlatformEnum::LEMMY, $url);
        $this->assertNotNull($foundInstance);
    }

    public function test_instance_creation_with_factory(): void
    {
        $instance = PlatformInstance::factory()->create();

        $this->assertInstanceOf(PlatformInstance::class, $instance);
        $this->assertEquals('lemmy', $instance->platform->value);
        $this->assertIsString($instance->name);
        $this->assertIsString($instance->url);
        $this->assertTrue($instance->is_active);
    }

    public function test_instance_creation_with_explicit_values(): void
    {
        $instance = PlatformInstance::create([
            'platform' => PlatformEnum::LEMMY,
            'url' => 'https://lemmy.world',
            'name' => 'Lemmy World',
            'description' => 'A general purpose Lemmy instance',
            'is_active' => false,
        ]);

        $this->assertEquals(PlatformEnum::LEMMY, $instance->platform);
        $this->assertEquals('https://lemmy.world', $instance->url);
        $this->assertEquals('Lemmy World', $instance->name);
        $this->assertEquals('A general purpose Lemmy instance', $instance->description);
        $this->assertFalse($instance->is_active);
    }

    public function test_instance_factory_states(): void
    {
        $inactiveInstance = PlatformInstance::factory()->inactive()->create();
        $this->assertFalse($inactiveInstance->is_active);

        $lemmyInstance = PlatformInstance::factory()->lemmy()->create();
        $this->assertEquals(PlatformEnum::LEMMY, $lemmyInstance->platform);
        $this->assertStringStartsWith('Lemmy ', $lemmyInstance->name);
        $this->assertStringStartsWith('https://lemmy.', $lemmyInstance->url);
    }

    public function test_instance_update(): void
    {
        $instance = PlatformInstance::factory()->create([
            'name' => 'Original Name',
            'is_active' => true,
        ]);

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

        $instance->refresh();

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

    public function test_instance_deletion(): void
    {
        $instance = PlatformInstance::factory()->create();
        $instanceId = $instance->id;

        $instance->delete();

        $this->assertDatabaseMissing('platform_instances', ['id' => $instanceId]);
    }

    public function test_instance_can_have_null_description(): void
    {
        $instance = PlatformInstance::factory()->create(['description' => null]);

        $this->assertNull($instance->description);
    }

    public function test_instance_can_have_empty_description(): void
    {
        $instance = PlatformInstance::factory()->create(['description' => '']);

        $this->assertEquals('', $instance->description);
    }

    public function test_instance_url_validation(): void
    {
        $validUrls = [
            'https://lemmy.world',
            'https://lemmy.ml',
            'https://beehaw.org',
            'http://localhost:8080',
        ];

        foreach ($validUrls as $url) {
            $instance = PlatformInstance::factory()->create(['url' => $url]);
            $this->assertEquals($url, $instance->url);
        }
    }

    public function test_instance_timestamps(): void
    {
        $instance = PlatformInstance::factory()->create();

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

    public function test_instance_can_have_multiple_languages(): void
    {
        $instance = PlatformInstance::factory()->create();
        $language1 = Language::factory()->create();
        $language2 = Language::factory()->create();
        $language3 = Language::factory()->create();

        // Attach multiple languages with different pivot data
        $instance->languages()->attach([
            $language1->id => ['platform_language_id' => 1, 'is_default' => true],
            $language2->id => ['platform_language_id' => 2, 'is_default' => false],
            $language3->id => ['platform_language_id' => 3, 'is_default' => false],
        ]);

        $languages = $instance->languages;

        $this->assertCount(3, $languages);

        // Test that we can access pivot data
        foreach ($languages as $language) {
            $this->assertNotNull($language->pivot->platform_language_id);
            $this->assertContains($language->pivot->is_default, [0, 1, true, false]);
        }

        // Only one should be default
        $defaultLanguages = $languages->filter(fn ($lang) => $lang->pivot->is_default);
        $this->assertCount(1, $defaultLanguages);
    }

    public function test_instance_channels_relationship_is_empty_by_default(): void
    {
        $instance = PlatformInstance::factory()->create();

        $this->assertCount(0, $instance->channels);
    }

    public function test_instance_languages_relationship_is_empty_by_default(): void
    {
        $instance = PlatformInstance::factory()->create();

        $this->assertCount(0, $instance->languages);
    }

    public function test_multiple_instances_with_same_platform(): void
    {
        $instance1 = PlatformInstance::factory()->create([
            'platform' => PlatformEnum::LEMMY,
            'name' => 'Lemmy World',
        ]);

        $instance2 = PlatformInstance::factory()->create([
            'platform' => PlatformEnum::LEMMY,
            'name' => 'Lemmy ML',
        ]);

        $this->assertEquals(PlatformEnum::LEMMY, $instance1->platform);
        $this->assertEquals(PlatformEnum::LEMMY, $instance2->platform);
        $this->assertNotEquals($instance1->id, $instance2->id);
        $this->assertNotEquals($instance1->name, $instance2->name);
    }

    public function test_instance_platform_enum_string_value(): void
    {
        $instance = PlatformInstance::factory()->create(['platform' => 'lemmy']);

        $this->assertEquals('lemmy', $instance->platform->value);
        $this->assertEquals(PlatformEnum::LEMMY, $instance->platform);
    }
}
