<?php

namespace Tests\Feature\Http\Controllers\Api\V1;

use App\Models\PlatformAccount;
use App\Models\PlatformChannel;
use App\Models\PlatformInstance;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;

class PlatformChannelsControllerTest extends TestCase
{
    use RefreshDatabase;

    private bool $instanceReachable = true;

    protected function setUp(): void
    {
        parent::setUp();
        Cache::flush();
        // A stub registered here cannot be overridden by a later Http::fake() for the
        // same pattern, so tests toggle the outcome through $instanceReachable instead.
        Http::fake(['*/api/v3/community/list*' => fn () => $this->instanceReachable
            ? Http::response([
                'communities' => [
                    ['community' => ['id' => 8, 'name' => 'test_channel', 'title' => 'Test Channel']],
                    ['community' => ['id' => 9, 'name' => 'tech_news', 'title' => 'Tech News']],
                ],
            ])
            : Http::response([], 503)]);
    }

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

        $response = $this->getJson('/api/v1/platform-channels');

        $response->assertStatus(200)
            ->assertJsonStructure([
                'success',
                'message',
                'data' => [
                    '*' => [
                        'id',
                        'platform_instance_id',
                        'channel_id',
                        'name',
                        'display_name',
                        'description',
                        'is_active',
                        'created_at',
                        'updated_at',
                        'platform_instance',
                    ],
                ],
            ])
            ->assertJson([
                'success' => true,
                'message' => 'Platform channels retrieved successfully.',
            ]);
    }

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

        // Create a platform account for this instance first
        PlatformAccount::factory()->create([
            'instance_url' => $instance->url,
            'is_active' => true,
        ]);

        $data = [
            'platform_instance_id' => $instance->id,
            'channel_id' => 8,
            'description' => 'A test channel',
        ];

        $response = $this->postJson('/api/v1/platform-channels', $data);

        $response->assertStatus(201)
            ->assertJsonStructure([
                'success',
                'message',
                'data' => [
                    'id',
                    'platform_instance_id',
                    'channel_id',
                    'name',
                    'display_name',
                    'description',
                    'is_active',
                    'created_at',
                    'updated_at',
                ],
            ])
            ->assertJson([
                'success' => true,
                'message' => 'Platform channel created successfully and linked to platform account!',
            ]);

        $this->assertDatabaseHas('platform_channels', [
            'platform_instance_id' => $instance->id,
            'channel_id' => 8,
        ]);
    }

    public function test_store_validates_required_fields(): void
    {
        $response = $this->postJson('/api/v1/platform-channels', []);

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['platform_instance_id', 'channel_id']);
    }

    public function test_store_validates_platform_instance_exists(): void
    {
        $data = [
            'platform_instance_id' => 999,
            'channel_id' => 8,
        ];

        $response = $this->postJson('/api/v1/platform-channels', $data);

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['platform_instance_id']);
    }

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

        $response = $this->postJson('/api/v1/platform-channels', [
            'platform_instance_id' => $instance->id,
            'channel_id' => 4242,
        ]);

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['channel_id']);

        $this->assertDatabaseCount('platform_channels', 0);
    }

    public function test_store_distinguishes_an_unreachable_instance_from_a_missing_community(): void
    {
        $this->instanceReachable = false;

        $instance = PlatformInstance::factory()->create();
        PlatformAccount::factory()->create([
            'instance_url' => $instance->url,
            'is_active' => true,
        ]);

        $response = $this->postJson('/api/v1/platform-channels', [
            'platform_instance_id' => $instance->id,
            'channel_id' => 8,
        ]);

        $response->assertStatus(422);
        $this->assertStringContainsString('Could not reach this instance', $response->json('message'));
        $this->assertDatabaseCount('platform_channels', 0);
    }

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

        $response = $this->postJson('/api/v1/platform-channels', [
            'platform_instance_id' => $instance->id,
            'channel_id' => 9,
        ]);

        $response->assertStatus(422)
            ->assertJsonValidationErrors(['channel_id']);

        $this->assertDatabaseCount('platform_channels', 1);
    }

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

        PlatformAccount::factory()->create([
            'instance_url' => $instanceB->url,
            'is_active' => true,
        ]);

        PlatformChannel::factory()->create([
            'platform_instance_id' => $instanceA->id,
            'name' => 'tech_news',
            'channel_id' => 9,
        ]);

        $response = $this->postJson('/api/v1/platform-channels', [
            'platform_instance_id' => $instanceB->id,
            'channel_id' => 9,
        ]);

        $response->assertStatus(201);

        $this->assertDatabaseCount('platform_channels', 2);
    }

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

        $response = $this->getJson("/api/v1/platform-channels/{$channel->id}");

        $response->assertStatus(200)
            ->assertJsonStructure([
                'success',
                'message',
                'data' => [
                    'id',
                    'platform_instance_id',
                    'channel_id',
                    'name',
                    'display_name',
                    'description',
                    'is_active',
                    'created_at',
                    'updated_at',
                    'platform_instance',
                ],
            ])
            ->assertJson([
                'success' => true,
                'message' => 'Platform channel retrieved successfully.',
                'data' => [
                    'id' => $channel->id,
                    'name' => $channel->name,
                ],
            ]);
    }

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

        $updateData = [
            'name' => 'Updated Channel',
            'display_name' => 'Updated Display Name',
            'description' => 'Updated description',
            'is_active' => false,
        ];

        $response = $this->putJson("/api/v1/platform-channels/{$channel->id}", $updateData);

        $response->assertStatus(200)
            ->assertJson([
                'success' => true,
                'message' => 'Platform channel updated successfully!',
            ]);

        $this->assertDatabaseHas('platform_channels', [
            'id' => $channel->id,
            'name' => 'Updated Channel',
            'display_name' => 'Updated Display Name',
            'is_active' => false,
        ]);
    }

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

        $response = $this->deleteJson("/api/v1/platform-channels/{$channel->id}");

        $response->assertStatus(200)
            ->assertJson([
                'success' => true,
                'message' => 'Platform channel deleted successfully!',
            ]);

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

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

        $response = $this->postJson("/api/v1/platform-channels/{$channel->id}/toggle");

        $response->assertStatus(200)
            ->assertJson([
                'success' => true,
                'message' => 'Platform channel activated successfully!',
            ]);

        $this->assertDatabaseHas('platform_channels', [
            'id' => $channel->id,
            'is_active' => true,
        ]);
    }

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

        $response = $this->postJson("/api/v1/platform-channels/{$channel->id}/toggle");

        $response->assertStatus(200)
            ->assertJson([
                'success' => true,
                'message' => 'Platform channel deactivated successfully!',
            ]);

        $this->assertDatabaseHas('platform_channels', [
            'id' => $channel->id,
            'is_active' => false,
        ]);
    }
}
