<?php

namespace Tests\Feature;

use App\Campaigns\Targeting\CountryCatalog;
use App\Campaigns\Targeting\CountryLookup;
use App\Models\Location;
use App\Models\PlatformLocation;
use Database\Seeders\CountryLocationSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery;
use RuntimeException;
use Tests\TestCase;

class CountryCatalogTest extends TestCase
{
    use RefreshDatabase;

    public function test_country_seed_is_repeatable_and_keeps_verified_mappings(): void
    {
        $this->seed(CountryLocationSeeder::class);
        $france = Location::query()->where('iso_code', 'FR')->sole();
        $mapping = PlatformLocation::factory()->create([
            'location_id' => $france->id,
            'platform' => 'google',
            'external_id' => 'geoTargetConstants/2250',
        ]);

        $this->seed(CountryLocationSeeder::class);

        $this->assertSame(249, Location::query()->where('type', 'country')->count());
        $this->assertSame('France', $france->fresh()->name);
        $this->assertSame($mapping->id, PlatformLocation::sole()->id);
        $this->assertSame([
            'US', 'GB', 'IN', 'CA', 'AU', 'DE', 'FR', 'ES', 'IT', 'NL', 'BR', 'MX', 'JP', 'SG', 'IE', 'NZ', 'CH', 'SE',
        ], Location::query()->where('type', 'country')->orderBy('id')->limit(18)->pluck('iso_code')->all());
    }

    public function test_exact_provider_match_is_saved_and_reused(): void
    {
        $lookup = Mockery::mock(CountryLookup::class);
        $lookup->shouldReceive('find')->once()->with('linkedin', 'CA', 'Canada', '123')
            ->andReturn(['id' => 'urn:li:geo:999', 'name' => 'Canada']);
        $this->app->instance(CountryLookup::class, $lookup);

        $catalog = app(CountryCatalog::class);
        $this->assertSame(['urn:li:geo:999'], $catalog->resolve('linkedin', ['CA'], '123'));
        $this->assertSame(['urn:li:geo:999'], $catalog->resolve('linkedin', ['CA'], '123'));
        $this->assertSame('CA', PlatformLocation::sole()->location->iso_code);
    }

    public function test_missing_provider_match_does_not_save_an_incorrect_location(): void
    {
        $lookup = Mockery::mock(CountryLookup::class);
        $lookup->shouldReceive('find')->once()->andReturn(null);
        $this->app->instance(CountryLookup::class, $lookup);

        try {
            app(CountryCatalog::class)->resolve('linkedin', ['CA'], '123');
            $this->fail('An unresolved location must fail before publication.');
        } catch (RuntimeException $exception) {
            $this->assertStringContainsString('mapping is not available for: CA', $exception->getMessage());
        }

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

    public function test_stale_mapping_is_refreshed_before_reuse(): void
    {
        $location = Location::factory()->create(['iso_code' => 'CA', 'country_code' => 'CA', 'name' => 'Canada']);
        PlatformLocation::factory()->create([
            'location_id' => $location->id,
            'platform' => 'linkedin',
            'external_id' => 'urn:li:geo:old',
            'verified_at' => now()->subDays(31),
        ]);

        $lookup = Mockery::mock(CountryLookup::class);
        $lookup->shouldReceive('find')->once()->with('linkedin', 'CA', 'Canada', '123')
            ->andReturn(['id' => 'urn:li:geo:new', 'name' => 'Canada']);
        $this->app->instance(CountryLookup::class, $lookup);

        $this->assertSame(['urn:li:geo:new'], app(CountryCatalog::class)->resolve('linkedin', ['CA'], '123'));
        $this->assertSame('urn:li:geo:new', PlatformLocation::sole()->external_id);
    }
}
