<?php

namespace Tests\Unit\Models;

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

class PlatformChannelTest extends TestCase
{
    use RefreshDatabase;

    public function test_fillable_fields(): void
    {
        $fillableFields = ['platform_instance_id', 'name', 'display_name', 'channel_id', 'description', 'language_id', 'is_active'];
        $channel = new PlatformChannel;

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

    public function test_table_name(): void
    {
        $channel = new PlatformChannel;

        $this->assertEquals('platform_channels', $channel->getTable());
    }

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

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

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

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

    public function test_channel_id_is_unique_per_platform_instance(): void
    {
        $instance = PlatformInstance::factory()->create();
        PlatformChannel::factory()->create([
            'platform_instance_id' => $instance->id,
            'name' => 'tech',
            'channel_id' => 7,
        ]);

        $this->expectException(UniqueConstraintViolationException::class);

        PlatformChannel::factory()->create([
            'platform_instance_id' => $instance->id,
            'name' => 'tech_alias',
            'channel_id' => 7,
        ]);
    }

    public function test_same_channel_id_allowed_across_different_instances(): void
    {
        $instanceA = PlatformInstance::factory()->create();
        $instanceB = PlatformInstance::factory()->create();

        PlatformChannel::factory()->create([
            'platform_instance_id' => $instanceA->id,
            'channel_id' => 7,
        ]);
        $second = PlatformChannel::factory()->create([
            'platform_instance_id' => $instanceB->id,
            'channel_id' => 7,
        ]);

        $this->assertDatabaseCount('platform_channels', 2);
        $this->assertSame(7, $second->channel_id);
    }

    public function test_belongs_to_platform_instance_relationship(): void
    {
        $instance = PlatformInstance::factory()->create();
        $channel = PlatformChannel::factory()->create(['platform_instance_id' => $instance->id]);

        $this->assertInstanceOf(PlatformInstance::class, $channel->platformInstance);
        $this->assertEquals($instance->id, $channel->platformInstance->id);
        $this->assertEquals($instance->name, $channel->platformInstance->name);
    }

    public function test_belongs_to_language_relationship(): void
    {
        $language = Language::factory()->create();
        $channel = PlatformChannel::factory()->create(['language_id' => $language->id]);

        $this->assertInstanceOf(Language::class, $channel->language);
        $this->assertEquals($language->id, $channel->language->id);
        $this->assertEquals($language->name, $channel->language->name);
    }

    public function test_belongs_to_many_platform_accounts_relationship(): void
    {
        $channel = PlatformChannel::factory()->create();
        $account1 = PlatformAccount::factory()->create();
        $account2 = PlatformAccount::factory()->create();

        // Attach accounts with pivot data
        $channel->platformAccounts()->attach($account1->id, [
            'is_active' => true,
            'priority' => 100,
        ]);

        $channel->platformAccounts()->attach($account2->id, [
            'is_active' => false,
            'priority' => 50,
        ]);

        $accounts = $channel->platformAccounts;

        $this->assertCount(2, $accounts);
        $this->assertTrue($accounts->contains('id', $account1->id));
        $this->assertTrue($accounts->contains('id', $account2->id));

        // Test pivot data
        $account1FromRelation = $accounts->find($account1->id);
        $this->assertEquals(1, $account1FromRelation->pivot->is_active);
        $this->assertEquals(100, $account1FromRelation->pivot->priority);

        $account2FromRelation = $accounts->find($account2->id);
        $this->assertEquals(0, $account2FromRelation->pivot->is_active);
        $this->assertEquals(50, $account2FromRelation->pivot->priority);
    }

    public function test_active_platform_accounts_relationship(): void
    {
        $channel = PlatformChannel::factory()->create();
        $activeAccount1 = PlatformAccount::factory()->create();
        $activeAccount2 = PlatformAccount::factory()->create();
        $inactiveAccount = PlatformAccount::factory()->create();

        // Attach accounts
        $channel->platformAccounts()->attach($activeAccount1->id, [
            'is_active' => true,
            'priority' => 100,
        ]);

        $channel->platformAccounts()->attach($activeAccount2->id, [
            'is_active' => true,
            'priority' => 200,
        ]);

        $channel->platformAccounts()->attach($inactiveAccount->id, [
            'is_active' => false,
            'priority' => 150,
        ]);

        $activeAccounts = $channel->activePlatformAccounts;

        $this->assertCount(2, $activeAccounts);
        $this->assertTrue($activeAccounts->contains('id', $activeAccount1->id));
        $this->assertTrue($activeAccounts->contains('id', $activeAccount2->id));
        $this->assertFalse($activeAccounts->contains('id', $inactiveAccount->id));
    }

    public function test_full_name_attribute(): void
    {
        $instance = PlatformInstance::factory()->create(['url' => 'https://lemmy.example.com']);
        $channel = PlatformChannel::factory()->create([
            'platform_instance_id' => $instance->id,
            'name' => 'technology',
        ]);

        $this->assertEquals('https://lemmy.example.com/c/technology', $channel->full_name);
    }

    public function test_belongs_to_many_feeds_relationship(): void
    {
        $channel = PlatformChannel::factory()->create();
        $feed1 = Feed::factory()->create();
        $feed2 = Feed::factory()->create();

        // Create routes (which act as pivot records)
        Route::create([
            'feed_id' => $feed1->id,
            'platform_channel_id' => $channel->id,
            'is_active' => true,
            'priority' => 100,
        ]);

        Route::create([
            'feed_id' => $feed2->id,
            'platform_channel_id' => $channel->id,
            'is_active' => false,
            'priority' => 50,
        ]);

        $feeds = $channel->feeds;

        $this->assertCount(2, $feeds);
        $this->assertTrue($feeds->contains('id', $feed1->id));
        $this->assertTrue($feeds->contains('id', $feed2->id));

        // Test pivot data
        $feed1FromRelation = $feeds->find($feed1->id);
        $this->assertEquals(1, $feed1FromRelation->pivot->is_active);
        $this->assertEquals(100, $feed1FromRelation->pivot->priority);
    }

    public function test_active_feeds_relationship(): void
    {
        $channel = PlatformChannel::factory()->create();
        $activeFeed1 = Feed::factory()->create();
        $activeFeed2 = Feed::factory()->create();
        $inactiveFeed = Feed::factory()->create();

        // Create routes
        Route::create([
            'feed_id' => $activeFeed1->id,
            'platform_channel_id' => $channel->id,
            'is_active' => true,
            'priority' => 100,
        ]);

        Route::create([
            'feed_id' => $activeFeed2->id,
            'platform_channel_id' => $channel->id,
            'is_active' => true,
            'priority' => 200,
        ]);

        Route::create([
            'feed_id' => $inactiveFeed->id,
            'platform_channel_id' => $channel->id,
            'is_active' => false,
            'priority' => 150,
        ]);

        $activeFeeds = $channel->activeFeeds;

        $this->assertCount(2, $activeFeeds);
        $this->assertTrue($activeFeeds->contains('id', $activeFeed1->id));
        $this->assertTrue($activeFeeds->contains('id', $activeFeed2->id));
        $this->assertFalse($activeFeeds->contains('id', $inactiveFeed->id));

        // Test ordering by priority descending
        $feedIds = $activeFeeds->pluck('id')->toArray();
        $this->assertEquals($activeFeed2->id, $feedIds[0]); // Priority 200
        $this->assertEquals($activeFeed1->id, $feedIds[1]); // Priority 100
    }

    public function test_channel_creation_with_factory(): void
    {
        $channel = PlatformChannel::factory()->create();

        $this->assertInstanceOf(PlatformChannel::class, $channel);
        $this->assertNotNull($channel->platform_instance_id);
        $this->assertIsString($channel->name);
        $this->assertIsInt($channel->channel_id);
        $this->assertIsBool($channel->is_active);
    }

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

        $channel = PlatformChannel::create([
            'platform_instance_id' => $instance->id,
            'name' => 'test_channel',
            'display_name' => 'Test Channel',
            'channel_id' => 123,
            'description' => 'A test channel',
            'language_id' => $language->id,
            'is_active' => false,
        ]);

        $this->assertEquals($instance->id, $channel->platform_instance_id);
        $this->assertEquals('test_channel', $channel->name);
        $this->assertEquals('Test Channel', $channel->display_name);
        $this->assertSame(123, $channel->channel_id);
        $this->assertEquals('A test channel', $channel->description);
        $this->assertEquals($language->id, $channel->language_id);
        $this->assertFalse($channel->is_active);
    }

    public function test_channel_update(): void
    {
        $channel = PlatformChannel::factory()->create([
            'name' => 'original_name',
            'is_active' => true,
        ]);

        $channel->update([
            'name' => 'updated_name',
            'is_active' => false,
        ]);

        $channel->refresh();

        $this->assertEquals('updated_name', $channel->name);
        $this->assertFalse($channel->is_active);
    }

    public function test_channel_deletion(): void
    {
        $channel = PlatformChannel::factory()->create();
        $channelId = $channel->id;

        $channel->delete();

        $this->assertDatabaseMissing('platform_channels', ['id' => $channelId]);
    }

    public function test_channel_with_display_name(): void
    {
        $channel = PlatformChannel::factory()->create([
            'name' => 'tech',
            'display_name' => 'Technology Discussion',
        ]);

        $this->assertEquals('tech', $channel->name);
        $this->assertEquals('Technology Discussion', $channel->display_name);
    }

    public function test_channel_without_display_name(): void
    {
        $channel = PlatformChannel::factory()->create([
            'name' => 'general',
            'display_name' => 'General',
        ]);

        $this->assertEquals('general', $channel->name);
        $this->assertEquals('General', $channel->display_name);
    }

    public function test_channel_timestamps(): void
    {
        $channel = PlatformChannel::factory()->create();

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

    public function test_channel_can_have_multiple_accounts_with_different_priorities(): void
    {
        $channel = PlatformChannel::factory()->create();
        $account1 = PlatformAccount::factory()->create();
        $account2 = PlatformAccount::factory()->create();
        $account3 = PlatformAccount::factory()->create();

        // Attach accounts with different priorities
        $channel->platformAccounts()->attach([
            $account1->id => ['is_active' => true, 'priority' => 300],
            $account2->id => ['is_active' => true, 'priority' => 100],
            $account3->id => ['is_active' => false, 'priority' => 200],
        ]);

        $allAccounts = $channel->platformAccounts;
        $activeAccounts = $channel->activePlatformAccounts;

        $this->assertCount(3, $allAccounts);
        $this->assertCount(2, $activeAccounts);

        // Test that we can access pivot data
        foreach ($allAccounts as $account) {
            $this->assertNotNull($account->pivot->priority);
            $this->assertIsInt($account->pivot->is_active);
        }
    }
}
