<?php

namespace Tests\Feature\Livewire;

use App\Livewire\Feeds;
use App\Models\Feed;
use App\Models\Language;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Tests\TestCase;

class FeedsTest extends TestCase
{
    use RefreshDatabase;

    public function test_add_button_renders_when_feeds_exist(): void
    {
        Feed::factory()->create(['name' => 'Existing Feed']);

        Livewire::test(Feeds::class)
            ->assertSee('Add Feed')
            ->assertSee('Existing Feed');
    }

    public function test_add_button_renders_in_empty_state(): void
    {
        Livewire::test(Feeds::class)
            ->assertSee('No feeds')
            ->assertSee('Add Feed');
    }

    public function test_open_create_modal_shows_modal(): void
    {
        Livewire::test(Feeds::class)
            ->assertSet('showCreateModal', false)
            ->call('openCreateModal')
            ->assertSet('showCreateModal', true);
    }

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

        Livewire::test(Feeds::class)
            ->call('openCreateModal')
            ->set('newProvider', 'guardian')
            ->set('newLanguageId', $language->id)
            ->call('createFeed')
            ->assertHasErrors(['newName' => 'required']);
    }

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

        Livewire::test(Feeds::class)
            ->call('openCreateModal')
            ->set('newName', 'Tech News')
            ->set('newLanguageId', $language->id)
            ->call('createFeed')
            ->assertHasErrors(['newProvider' => 'required']);
    }

    public function test_create_feed_requires_language(): void
    {
        Livewire::test(Feeds::class)
            ->call('openCreateModal')
            ->set('newName', 'Tech News')
            ->set('newProvider', 'guardian')
            ->call('createFeed')
            ->assertHasErrors(['newLanguageId' => 'required']);
    }

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

        Livewire::test(Feeds::class)
            ->call('openCreateModal')
            ->set('newName', 'Tech News')
            ->set('newProvider', 'nonexistent')
            ->set('newLanguageId', $language->id)
            ->call('createFeed')
            ->assertHasErrors('newProvider');

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

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

        Livewire::test(Feeds::class)
            ->call('openCreateModal')
            ->set('newName', 'Guardian News')
            ->set('newProvider', 'guardian')
            ->set('newLanguageId', $language->id)
            ->set('newDescription', 'British daily')
            ->call('createFeed')
            ->assertHasNoErrors()
            ->assertSet('showCreateModal', false);

        $this->assertDatabaseHas('feeds', [
            'name' => 'Guardian News',
            'provider' => 'guardian',
            'language_id' => $language->id,
            'url' => 'https://www.theguardian.com/international/rss',
            'description' => 'British daily',
            'is_active' => true,
        ]);
    }

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

        Livewire::test(Feeds::class)
            ->call('openCreateModal')
            ->set('newName', 'Guardian News')
            ->set('newProvider', 'guardian')
            ->set('newLanguageId', $language->id)
            ->call('createFeed')
            ->assertHasNoErrors();

        $this->assertDatabaseHas('feeds', [
            'name' => 'Guardian News',
            'description' => null,
        ]);
    }

    public function test_create_feed_surfaces_invalid_provider_language_combination(): void
    {
        // Belga only supports 'en'; a non-'en' language triggers InvalidArgumentException in the action.
        $language = Language::factory()->create(['short_code' => 'nl', 'name' => 'Dutch', 'is_active' => true]);

        Livewire::test(Feeds::class)
            ->call('openCreateModal')
            ->set('newName', 'Belga NL')
            ->set('newProvider', 'belga')
            ->set('newLanguageId', $language->id)
            ->call('createFeed')
            ->assertHasErrors('newProvider')
            ->assertSet('showCreateModal', true);

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

    public function test_toggle_flips_active_state(): void
    {
        $feed = Feed::factory()->create(['is_active' => true]);

        Livewire::test(Feeds::class)
            ->call('toggle', $feed->id);

        $this->assertFalse($feed->fresh()->is_active);
    }

    public function test_feed_cards_show_an_edit_action(): void
    {
        Feed::factory()->create(['name' => 'VRT Nieuws']);

        Livewire::test(Feeds::class)
            ->assertSee('Edit VRT Nieuws');
    }

    public function test_open_edit_modal_prefills_the_current_values(): void
    {
        $feed = Feed::factory()->create([
            'name' => 'VRT Nieuws',
            'description' => 'Flemish public broadcaster',
        ]);

        Livewire::test(Feeds::class)
            ->assertSet('editingFeedId', null)
            ->call('openEditModal', $feed->id)
            ->assertSet('editingFeedId', $feed->id)
            ->assertSet('editName', 'VRT Nieuws')
            ->assertSet('editDescription', 'Flemish public broadcaster')
            ->assertSee('Edit Feed');
    }

    public function test_open_edit_modal_prefills_a_null_description_as_blank(): void
    {
        $feed = Feed::factory()->create(['description' => null]);

        Livewire::test(Feeds::class)
            ->call('openEditModal', $feed->id)
            ->assertSet('editDescription', '');
    }

    public function test_update_feed_persists_the_changes_and_closes_the_modal(): void
    {
        $feed = Feed::factory()->create([
            'name' => 'Old Name',
            'description' => 'Old description',
        ]);

        Livewire::test(Feeds::class)
            ->call('openEditModal', $feed->id)
            ->set('editName', 'New Name')
            ->set('editDescription', 'New description')
            ->call('updateFeed')
            ->assertSet('editingFeedId', null)
            ->assertHasNoErrors();

        $feed->refresh();

        $this->assertSame('New Name', $feed->name);
        $this->assertSame('New description', $feed->description);
    }

    public function test_update_feed_requires_a_name(): void
    {
        $feed = Feed::factory()->create(['name' => 'Original']);

        Livewire::test(Feeds::class)
            ->call('openEditModal', $feed->id)
            ->set('editName', '')
            ->call('updateFeed')
            ->assertHasErrors(['editName' => 'required']);

        $this->assertSame('Original', $feed->fresh()->name);
    }

    public function test_update_feed_rejects_a_name_over_the_length_limit(): void
    {
        $feed = Feed::factory()->create(['name' => 'Original']);

        Livewire::test(Feeds::class)
            ->call('openEditModal', $feed->id)
            ->set('editName', str_repeat('a', 256))
            ->call('updateFeed')
            ->assertHasErrors(['editName' => 'max']);

        $this->assertSame('Original', $feed->fresh()->name);
    }

    public function test_update_feed_stores_a_blank_description_as_null(): void
    {
        $feed = Feed::factory()->create(['description' => 'Has one']);

        Livewire::test(Feeds::class)
            ->call('openEditModal', $feed->id)
            ->set('editDescription', '')
            ->call('updateFeed');

        $this->assertNull($feed->fresh()->description);
    }

    public function test_update_feed_leaves_the_source_identity_untouched(): void
    {
        $feed = Feed::factory()->create(['name' => 'Original']);
        $before = $feed->only(['url', 'provider', 'language_id', 'type']);

        Livewire::test(Feeds::class)
            ->call('openEditModal', $feed->id)
            ->set('editName', 'Renamed')
            ->call('updateFeed');

        $this->assertSame($before, $feed->fresh()->only(['url', 'provider', 'language_id', 'type']));
    }

    public function test_close_edit_modal_discards_the_edit(): void
    {
        $feed = Feed::factory()->create(['name' => 'Original']);

        Livewire::test(Feeds::class)
            ->call('openEditModal', $feed->id)
            ->set('editName', 'Discarded')
            ->call('closeEditModal')
            ->assertSet('editingFeedId', null);

        $this->assertSame('Original', $feed->fresh()->name);
    }

    public function test_update_feed_does_nothing_without_an_open_modal(): void
    {
        $feed = Feed::factory()->create(['name' => 'Original']);

        Livewire::test(Feeds::class)
            ->set('editName', 'Should not apply')
            ->call('updateFeed')
            ->assertHasNoErrors();

        $this->assertSame('Original', $feed->fresh()->name);
    }
}
