<?php

namespace Tests\Feature;

use App\Actions\CreateRouteArticlesAction;
use App\Actions\FetchArticleDataAction;
use App\Actions\ValidateArticleAction;
use App\Enums\ApprovalStatusEnum;
use App\Events\NewArticleFetched;
use App\Listeners\ValidateArticleListener;
use App\Models\Article;
use App\Models\ArticlePublication;
use App\Models\Feed;
use App\Models\Keyword;
use App\Models\Route;
use App\Models\RouteArticle;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery;
use Tests\TestCase;

class ValidateArticleListenerTest extends TestCase
{
    use RefreshDatabase;

    private function createListenerWithMockedFetcher(?string $content = 'Some article content'): ValidateArticleListener
    {
        $articleFetcher = Mockery::mock(FetchArticleDataAction::class);
        $articleFetcher->shouldReceive('execute')->andReturn(
            $content ? [
                'title' => 'Test Title',
                'description' => 'Test description',
                'full_article' => $content,
            ] : []
        );

        return new ValidateArticleListener(
            new ValidateArticleAction($articleFetcher, new CreateRouteArticlesAction)
        );
    }

    protected function tearDown(): void
    {
        Mockery::close();
        parent::tearDown();
    }

    public function test_listener_validates_article_and_creates_route_articles(): void
    {
        $feed = Feed::factory()->create();
        /** @var Route $route */
        $route = Route::factory()->active()->create(['feed_id' => $feed->id]);
        Keyword::factory()->active()->create([
            'feed_id' => $feed->id,
            'platform_channel_id' => $route->platform_channel_id,
            'keyword' => 'Belgium',
        ]);

        $article = Article::factory()->create([
            'feed_id' => $feed->id,
        ]);

        $listener = $this->createListenerWithMockedFetcher('Article about Belgium');
        $listener->handle(new NewArticleFetched($article));

        $article->refresh();
        $this->assertNotNull($article->validated_at);

        $routeArticle = RouteArticle::where('article_id', $article->id)->first();
        $this->assertNotNull($routeArticle);
        $this->assertEquals(ApprovalStatusEnum::PENDING, $routeArticle->approval_status);
    }

    public function test_listener_skips_already_validated_articles(): void
    {
        $feed = Feed::factory()->create();
        Route::factory()->active()->create(['feed_id' => $feed->id]);

        $article = Article::factory()->create([
            'feed_id' => $feed->id,
            'validated_at' => now(),
        ]);

        $listener = $this->createListenerWithMockedFetcher();
        $listener->handle(new NewArticleFetched($article));

        $this->assertCount(0, RouteArticle::where('article_id', $article->id)->get());
    }

    public function test_listener_skips_articles_with_existing_publication(): void
    {
        $feed = Feed::factory()->create();
        Route::factory()->active()->create(['feed_id' => $feed->id]);

        $article = Article::factory()->create([
            'feed_id' => $feed->id,
        ]);

        ArticlePublication::create([
            'article_id' => $article->id,
            'post_id' => 'test-post-id',
            'platform_channel_id' => 1,
            'published_at' => now(),
            'published_by' => 'test-user',
        ]);

        $listener = $this->createListenerWithMockedFetcher();
        $listener->handle(new NewArticleFetched($article));

        $this->assertCount(0, RouteArticle::where('article_id', $article->id)->get());
    }

    public function test_listener_handles_validation_errors_gracefully(): void
    {
        $articleFetcher = Mockery::mock(FetchArticleDataAction::class);
        $articleFetcher->shouldReceive('execute')->andThrow(new \Exception('Fetch failed'));

        $listener = new ValidateArticleListener(
            new ValidateArticleAction($articleFetcher, new CreateRouteArticlesAction)
        );

        $feed = Feed::factory()->create();
        $article = Article::factory()->create([
            'feed_id' => $feed->id,
        ]);

        $listener->handle(new NewArticleFetched($article));

        $this->assertNull($article->fresh()->validated_at);
        $this->assertCount(0, RouteArticle::where('article_id', $article->id)->get());
    }
}
