<?php

namespace Tests\Unit\Actions;

use App\Models\Article;
use App\Models\Feed;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Http;
use Mockery;
use Tests\TestCase;
use Tests\Traits\CreatesFetchActions;

class FetchRssArticlesFeedTest extends TestCase
{
    use CreatesFetchActions, RefreshDatabase;

    private string $sampleRss;

    protected function setUp(): void
    {
        parent::setUp();

        $this->sampleRss = <<<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>The Guardian - International</title>
        <link>https://www.theguardian.com/international</link>
        <item>
            <title>First Article Title</title>
            <link>https://www.theguardian.com/world/2026/mar/08/first-article</link>
            <description>First article description</description>
            <pubDate>Sun, 08 Mar 2026 12:00:00 GMT</pubDate>
        </item>
        <item>
            <title>Second Article Title</title>
            <link>https://www.theguardian.com/world/2026/mar/08/second-article</link>
            <description>Second article description</description>
            <pubDate>Sun, 08 Mar 2026 11:00:00 GMT</pubDate>
        </item>
    </channel>
</rss>
XML;
    }

    public function test_get_articles_from_rss_feed_returns_collection(): void
    {
        Http::fake(['*' => Http::response($this->sampleRss, 200)]);

        $feed = Feed::factory()->create([
            'type' => 'rss',
            'provider' => 'guardian',
            'url' => 'https://www.theguardian.com/international/rss',
        ]);

        $fetcher = $this->createFeedFetcher();
        $result = $fetcher->execute($feed);

        $this->assertInstanceOf(Collection::class, $result);
    }

    public function test_get_articles_from_rss_feed_creates_articles(): void
    {
        Http::fake(['*' => Http::response($this->sampleRss, 200)]);

        $feed = Feed::factory()->create([
            'type' => 'rss',
            'provider' => 'guardian',
            'url' => 'https://www.theguardian.com/international/rss',
        ]);

        $fetcher = $this->createFeedFetcher();
        $result = $fetcher->execute($feed);

        $this->assertCount(2, $result);
        $this->assertDatabaseHas('articles', [
            'url' => 'https://www.theguardian.com/world/2026/mar/08/first-article',
            'feed_id' => $feed->id,
        ]);
        $this->assertDatabaseHas('articles', [
            'url' => 'https://www.theguardian.com/world/2026/mar/08/second-article',
            'feed_id' => $feed->id,
        ]);
    }

    public function test_get_articles_from_rss_feed_does_not_duplicate_existing(): void
    {
        Http::fake(['*' => Http::response($this->sampleRss, 200)]);

        $feed = Feed::factory()->create([
            'type' => 'rss',
            'provider' => 'guardian',
            'url' => 'https://www.theguardian.com/international/rss',
        ]);

        Article::factory()->create([
            'url' => 'https://www.theguardian.com/world/2026/mar/08/first-article',
            'feed_id' => $feed->id,
        ]);

        $fetcher = $this->createFeedFetcher();
        $result = $fetcher->execute($feed);

        $this->assertCount(2, $result);
        $this->assertEquals(1, Article::where('url', 'https://www.theguardian.com/world/2026/mar/08/first-article')->count());
    }

    public function test_get_articles_from_rss_feed_returns_known_articles_when_none_are_new(): void
    {
        Http::fake(['*' => Http::response($this->sampleRss, 200)]);

        $feed = Feed::factory()->create([
            'type' => 'rss',
            'provider' => 'guardian',
            'url' => 'https://www.theguardian.com/international/rss',
        ]);

        Article::factory()->create([
            'url' => 'https://www.theguardian.com/world/2026/mar/08/first-article',
            'feed_id' => $feed->id,
        ]);
        Article::factory()->create([
            'url' => 'https://www.theguardian.com/world/2026/mar/08/second-article',
            'feed_id' => $feed->id,
        ]);

        $countBeforeFetch = Article::count();

        $fetcher = $this->createFeedFetcher();
        $result = $fetcher->execute($feed);

        $this->assertCount(2, $result);
        $this->assertSame($countBeforeFetch, Article::count());
    }

    public function test_get_articles_from_rss_feed_handles_invalid_xml(): void
    {
        Http::fake(['*' => Http::response('this is not xml', 200)]);

        $feed = Feed::factory()->create([
            'type' => 'rss',
            'provider' => 'guardian',
            'url' => 'https://www.theguardian.com/international/rss',
        ]);

        $fetcher = $this->createFeedFetcher();
        $result = $fetcher->execute($feed);

        $this->assertInstanceOf(Collection::class, $result);
        $this->assertEmpty($result);
    }

    public function test_get_articles_from_rss_feed_handles_empty_channel(): void
    {
        Http::fake([
            '*' => Http::response('<?xml version="1.0"?><rss><channel><title>Empty</title></channel></rss>', 200),
        ]);

        $feed = Feed::factory()->create([
            'type' => 'rss',
            'provider' => 'guardian',
            'url' => 'https://www.theguardian.com/international/rss',
        ]);

        $fetcher = $this->createFeedFetcher();
        $result = $fetcher->execute($feed);

        $this->assertEmpty($result);
    }

    public function test_get_articles_from_rss_feed_handles_http_failure(): void
    {
        Http::fake(['*' => Http::response('Server Error', 500)]);

        $feed = Feed::factory()->create([
            'type' => 'rss',
            'provider' => 'guardian',
            'url' => 'https://www.theguardian.com/international/rss',
        ]);

        $fetcher = $this->createFeedFetcher();
        $result = $fetcher->execute($feed);

        $this->assertEmpty($result);
    }

    public function test_get_articles_from_belga_rss_feed_creates_articles(): void
    {
        $belgaRss = <<<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>Belga News Agency</title>
        <link>https://www.belganewsagency.eu</link>
        <item>
            <title>Belgium announces new climate plan</title>
            <link>https://www.belganewsagency.eu/belgium-announces-new-climate-plan</link>
            <description>Belgium has unveiled a comprehensive climate strategy.</description>
            <pubDate>Sun, 08 Mar 2026 10:00:00 GMT</pubDate>
        </item>
        <item>
            <title>EU summit concludes in Brussels</title>
            <link>https://www.belganewsagency.eu/eu-summit-concludes-in-brussels</link>
            <description>European leaders reached agreement on key issues.</description>
            <pubDate>Sun, 08 Mar 2026 09:00:00 GMT</pubDate>
        </item>
    </channel>
</rss>
XML;

        Http::fake(['*' => Http::response($belgaRss, 200)]);

        $feed = Feed::factory()->create([
            'type' => 'rss',
            'provider' => 'belga',
            'url' => 'https://www.belganewsagency.eu/feed',
        ]);

        $fetcher = $this->createFeedFetcher();
        $result = $fetcher->execute($feed);

        $this->assertCount(2, $result);
        $this->assertDatabaseHas('articles', [
            'url' => 'https://www.belganewsagency.eu/belgium-announces-new-climate-plan',
            'feed_id' => $feed->id,
        ]);
        $this->assertDatabaseHas('articles', [
            'url' => 'https://www.belganewsagency.eu/eu-summit-concludes-in-brussels',
            'feed_id' => $feed->id,
        ]);
    }

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