<?php

namespace Tests\Feature\Livewire;

use App\Enums\ActivityTypeEnum;
use App\Livewire\Activity;
use App\Models\ActivityLog;
use App\Models\Article;
use App\Models\Feed;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Livewire\Livewire;
use Tests\TestCase;

class ActivityTest extends TestCase
{
    use RefreshDatabase;

    public function test_renders_successfully(): void
    {
        Livewire::test(Activity::class)->assertStatus(200);
    }

    public function test_shows_recent_entries(): void
    {
        ActivityLog::factory()->create(['message' => 'Published something']);

        Livewire::test(Activity::class)->assertSee('Published something');
    }

    public function test_filtering_by_type_hides_other_types(): void
    {
        ActivityLog::factory()->type(ActivityTypeEnum::PUBLISH)->create(['message' => 'A publish entry']);
        ActivityLog::factory()->type(ActivityTypeEnum::FETCH)->create(['message' => 'A fetch entry']);

        Livewire::test(Activity::class)
            ->set('type', ActivityTypeEnum::PUBLISH->value)
            ->assertSee('A publish entry')
            ->assertDontSee('A fetch entry');
    }

    public function test_entries_outside_the_day_range_are_hidden(): void
    {
        ActivityLog::factory()->loggedAt(now()->subHours(2))->create(['message' => 'Recent entry']);
        ActivityLog::factory()->loggedAt(now()->subDays(10))->create(['message' => 'Old entry']);

        Livewire::test(Activity::class)
            ->set('days', 1)
            ->assertSee('Recent entry')
            ->assertDontSee('Old entry');
    }

    public function test_changing_a_filter_resets_pagination(): void
    {
        ActivityLog::factory()->count(30)->create();

        Livewire::test(Activity::class)
            ->call('setPage', 2)
            ->set('type', ActivityTypeEnum::PUBLISH->value)
            ->assertSet('paginators.page', 1);
    }

    public function test_entry_without_a_subject_renders(): void
    {
        ActivityLog::factory()->create(['message' => 'No subject entry', 'subject_type' => null, 'subject_id' => null]);

        Livewire::test(Activity::class)
            ->assertStatus(200)
            ->assertSee('No subject entry');
    }

    public function test_entry_with_a_deleted_subject_renders(): void
    {
        $article = Article::factory()->create();
        ActivityLog::factory()->forSubject($article)->create(['message' => 'Dangling subject']);
        $article->delete();

        Livewire::test(Activity::class)
            ->assertStatus(200)
            ->assertSee('Dangling subject');
    }

    public function test_empty_state_is_shown_when_there_is_no_activity(): void
    {
        Livewire::test(Activity::class)->assertSee('No activity in this period.');
    }

    public function test_an_article_subject_shows_its_feed_name(): void
    {
        $feed = Feed::factory()->create(['name' => 'VRT News']);
        $article = Article::factory()->create(['feed_id' => $feed->id]);
        ActivityLog::factory()->forSubject($article)->create(['message' => 'Published something']);

        Livewire::test(Activity::class)->assertSee('VRT News');
    }

    public function test_subjects_are_eager_loaded(): void
    {
        $feed = Feed::factory()->create();

        foreach (range(1, 5) as $i) {
            $article = Article::factory()->create(['feed_id' => $feed->id]);
            ActivityLog::factory()->forSubject($article)->create();
        }

        DB::enableQueryLog();
        Livewire::test(Activity::class);
        $queries = count(DB::getQueryLog());
        DB::disableQueryLog();

        $this->assertLessThan(10, $queries);
    }

    public function test_a_reason_in_context_is_shown_under_the_message(): void
    {
        ActivityLog::factory()->create([
            'message' => 'Failed to publish something',
            'context' => ['reason' => 'Could not recover the article content'],
        ]);

        Livewire::test(Activity::class)->assertSee('Could not recover the article content');
    }

    public function test_a_message_containing_markup_is_escaped(): void
    {
        ActivityLog::factory()->create(['message' => 'Published "<script>alert(1)</script>"']);

        Livewire::test(Activity::class)
            ->assertDontSee('<script>alert(1)</script>', false)
            ->assertSee('&lt;script&gt;', false);
    }
}
