<?php

namespace Tests\Feature;

use App\Campaigns\Targeting\TargetingSelections;
use App\Models\Brief;
use App\Models\Campaign;
use App\Models\Location;
use App\Models\TargetingSet;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use RuntimeException;
use Tests\TestCase;

class TargetingSelectionsTest extends TestCase
{
    use RefreshDatabase;

    private function campaign(?Brief $brief = null): Campaign
    {
        $brief ??= Brief::factory()->create();

        return Campaign::create([
            'user_id' => $brief->user_id,
            'brief_id' => $brief->getKey(),
            'name' => 'Targeting test campaign',
            'platform' => 'meta',
            'status' => 'draft',
        ]);
    }

    public function test_legacy_country_json_is_read_without_a_targeting_set(): void
    {
        $brief = Brief::factory()->create(['locations' => ['countries' => ['US']]]);
        $campaign = $this->campaign($brief);

        $this->assertSame(['US'], app(TargetingSelections::class)->countries($campaign));
        $this->assertDatabaseCount('targeting_sets', 0);
    }

    public function test_country_changes_preserve_other_location_selections_and_json_fields(): void
    {
        $campaign = $this->campaign();
        $campaign->update(['locations' => ['countries' => ['US'], 'cities' => ['legacy-city']]]);
        $set = TargetingSet::factory()->forCampaign($campaign)->create();
        $city = Location::create([
            'type' => 'city',
            'name' => 'Springfield',
            'country_code' => 'US',
            'source' => 'google',
            'source_key' => 'geoTargetConstants/12345',
        ]);
        $set->locations()->create([
            'location_id' => $city->getKey(),
            'operation' => 'include',
            'kind' => 'city',
            'display_label' => 'Springfield, Illinois, United States',
            'country_code' => 'US',
        ]);

        $updated = app(TargetingSelections::class)->saveCampaignCountries($campaign, ['GB'], expectedRevision: 1);

        $this->assertSame(2, $updated->revision);
        $this->assertSame(['GB'], app(TargetingSelections::class)->countries($campaign->fresh()));
        $this->assertSame(['legacy-city'], $campaign->fresh()->locations['cities']);
        $this->assertSame(1, $updated->locations()->where('kind', 'city')->count());
        $this->assertSame(1, $updated->locations()->where('kind', 'country')->count());
    }

    public function test_stale_revision_does_not_change_targeting(): void
    {
        $campaign = $this->campaign();
        $selections = app(TargetingSelections::class);
        $selections->saveCampaignCountries($campaign, ['US'], expectedRevision: 0);

        try {
            $selections->saveCampaignCountries($campaign, ['CA'], expectedRevision: 0);
            $this->fail('Expected a revision conflict.');
        } catch (RuntimeException) {
            $this->assertSame(['US'], $selections->countries($campaign->fresh()));
            $this->assertSame(['US'], $campaign->fresh()->locations['countries']);
        }
    }

    public function test_inherit_and_explicit_clear_are_distinct(): void
    {
        $brief = Brief::factory()->create(['locations' => ['countries' => ['US']]]);
        $campaign = $this->campaign($brief);
        $set = TargetingSet::factory()->forCampaign($campaign)->create(['mode' => 'inherit']);

        $this->assertSame(['US'], app(TargetingSelections::class)->countries($campaign->fresh()));

        $set->update(['mode' => 'clear']);
        $this->assertSame([], app(TargetingSelections::class)->countries($campaign->fresh()));
    }

    public function test_backfill_is_repeatable_and_preserves_legacy_campaign_json(): void
    {
        $brief = Brief::factory()->create(['locations' => ['countries' => ['US']]]);
        $inherited = $this->campaign($brief);
        $overridden = $this->campaign($brief);
        $overridden->update(['locations' => ['countries' => ['GB'], 'cities' => ['keep-me']]]);
        $imported = Campaign::create([
            'user_id' => User::factory()->create()->getKey(),
            'name' => 'Imported',
            'platform' => 'meta',
            'status' => 'published',
            'locations' => ['countries' => ['CA']],
        ]);
        $originalJson = $overridden->getRawOriginal('locations');

        $this->artisan('targeting:backfill', ['--chunk' => 1])->assertSuccessful();
        $this->artisan('targeting:backfill', ['--chunk' => 1])->assertSuccessful();

        $this->assertDatabaseCount('targeting_sets', 4);
        $this->assertSame('inherit', $inherited->fresh()->targetingSet->mode);
        $this->assertSame(['US'], app(TargetingSelections::class)->countries($inherited->fresh()));
        $this->assertSame(['GB'], app(TargetingSelections::class)->countries($overridden->fresh()));
        $this->assertSame(['CA'], app(TargetingSelections::class)->countries($imported->fresh()));
        $this->assertSame($originalJson, $overridden->fresh()->getRawOriginal('locations'));
        $this->assertSame(['keep-me'], $overridden->fresh()->locations['cities']);
    }
}
