<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use stdClass;
use Tests\TestCase;

/**
 * The migration has already run by the time RefreshDatabase hands over, so
 * these tests seed a pre-migration state and invoke up() against it directly.
 */
class SyncBelgaFeedMigrationTest extends TestCase
{
    use RefreshDatabase;

    private const DEAD_RSS_URL = 'https://www.belganewsagency.eu/feed';

    private function runMigration(): void
    {
        $migration = require database_path('migrations/2024_01_01_000012_sync_belga_feed_to_website_discovery.php');

        $migration->up();
    }

    private function findFeed(int $id): stdClass
    {
        $feed = DB::table('feeds')->find($id);

        $this->assertInstanceOf(stdClass::class, $feed);

        return $feed;
    }

    private function targetUrl(): string
    {
        $url = config('feed.providers.belga.languages.en.url');

        $this->assertIsString($url);

        return $url;
    }

    private function seedFeed(string $url, string $type, bool $isActive = true, string $provider = 'belga'): int
    {
        return DB::table('feeds')->insertGetId([
            'name' => 'Belga',
            'provider' => $provider,
            'type' => $type,
            'url' => $url,
            'is_active' => $isActive,
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    public function test_converts_a_feed_still_on_the_dead_rss_url(): void
    {
        DB::table('feeds')->delete();
        $id = $this->seedFeed(self::DEAD_RSS_URL, 'rss');

        $this->runMigration();

        $feed = $this->findFeed($id);

        $this->assertSame('website', $feed->type);
        $this->assertSame($this->targetUrl(), $feed->url);
        $this->assertTrue((bool) $feed->is_active);
    }

    public function test_is_idempotent_when_the_feed_is_already_migrated(): void
    {
        DB::table('feeds')->delete();
        $id = $this->seedFeed($this->targetUrl(), 'website');

        $this->runMigration();
        $this->runMigration();

        $this->assertSame(1, DB::table('feeds')->where('provider', 'belga')->count());

        $feed = $this->findFeed($id);
        $this->assertSame('website', $feed->type);
        $this->assertSame($this->targetUrl(), $feed->url);
    }

    public function test_deactivates_superseded_rows_instead_of_colliding_on_the_unique_url(): void
    {
        DB::table('feeds')->delete();
        $staleId = $this->seedFeed(self::DEAD_RSS_URL, 'rss');
        $currentId = $this->seedFeed($this->targetUrl(), 'website');

        $this->runMigration();

        // Both rows survive: routes.feed_id cascades on delete, so a superseded
        // feed is deactivated rather than removed.
        $this->assertSame(2, DB::table('feeds')->where('provider', 'belga')->count());

        $current = $this->findFeed($currentId);
        $this->assertTrue((bool) $current->is_active);
        $this->assertSame($this->targetUrl(), $current->url);
        $this->assertSame('website', $current->type);

        $stale = $this->findFeed($staleId);
        $this->assertFalse((bool) $stale->is_active);
    }

    public function test_adopts_the_oldest_row_when_none_is_on_the_target_url(): void
    {
        DB::table('feeds')->delete();
        $oldestId = $this->seedFeed(self::DEAD_RSS_URL, 'rss');
        $newerId = $this->seedFeed('https://capi.belga.press/belgapress/api/public/pressreleases?count=6', 'website');

        $this->runMigration();

        // Neither row matches config, so the migration falls back to the lowest
        // id — the oldest row, which is the one routes are most likely tied to.
        $oldest = $this->findFeed($oldestId);
        $this->assertSame($this->targetUrl(), $oldest->url);
        $this->assertSame('website', $oldest->type);
        $this->assertTrue((bool) $oldest->is_active);

        $this->assertFalse((bool) $this->findFeed($newerId)->is_active);
    }

    public function test_leaves_other_providers_untouched(): void
    {
        DB::table('feeds')->delete();
        $vrtId = $this->seedFeed('https://www.vrt.be/vrtnws/nl/', 'website', true, 'vrt');
        // Seed a belga row too, so the migration actually runs its updates
        // rather than bailing out at the "no belga feed" guard.
        $this->seedFeed(self::DEAD_RSS_URL, 'rss');

        $this->runMigration();

        $vrt = $this->findFeed($vrtId);

        $this->assertSame('https://www.vrt.be/vrtnws/nl/', $vrt->url);
        $this->assertSame('website', $vrt->type);
        $this->assertTrue((bool) $vrt->is_active);
    }

    public function test_down_is_a_deliberate_no_op(): void
    {
        DB::table('feeds')->delete();
        $id = $this->seedFeed($this->targetUrl(), 'website');

        $migration = require database_path('migrations/2024_01_01_000012_sync_belga_feed_to_website_discovery.php');
        $migration->down();

        // Rolling back must not restore the retired RSS url.
        $feed = $this->findFeed($id);
        $this->assertSame($this->targetUrl(), $feed->url);
        $this->assertSame('website', $feed->type);
    }

    public function test_does_nothing_when_no_belga_feed_exists(): void
    {
        DB::table('feeds')->delete();

        $this->runMigration();

        $this->assertSame(0, DB::table('feeds')->count());
    }

    public function test_does_nothing_when_the_configured_url_is_missing(): void
    {
        DB::table('feeds')->delete();
        config(['feed.providers.belga.languages.en.url' => '']);
        $id = $this->seedFeed(self::DEAD_RSS_URL, 'rss');

        $this->runMigration();

        $feed = $this->findFeed($id);

        $this->assertSame('rss', $feed->type);
        $this->assertSame(self::DEAD_RSS_URL, $feed->url);
    }
}
