<?php

namespace Tests\Feature;

use App\Models\Campaign;
use App\Models\CampaignPerformanceHourStat;
use App\Models\CampaignPerformanceProfile;
use App\Models\CampaignPerformanceStat;
use App\Models\CampaignPerformanceSuggestion;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;

class CampaignPerformanceProfileSyncTest extends TestCase
{
    use RefreshDatabase;

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

        $this->travelTo('2026-09-22 12:00:00');

        config([
            'campaign-performance.platforms' => ['meta'],
            'campaign-performance.external_ids' => [],
            'campaign-performance.limit' => 5,
            'campaign-performance.backfill_days' => 2,
            'campaign-performance.daily_lookback_hours' => 24,
            'campaign-performance.llm_enabled' => false,
            'platforms.meta.token' => 'test-token',
            'platforms.meta.version' => 'v23.0',
            'platforms.guardrails.retry_backoff_ms' => 0,
            'platforms.guardrails.allowed_ad_accounts' => ['act_111'],
        ]);
    }

    public function test_dump_syncs_a_meta_profile_with_regions_and_learning(): void
    {
        $campaign = Campaign::create([
            'user_id' => User::factory()->create()->id,
            'name' => 'Italy packages',
            'platform' => 'meta',
            'status' => 'published',
            'budget' => 20,
            'objective' => 'OUTCOME_TRAFFIC',
            'ad_account_id' => 'act_111',
            'external_campaign_id' => '1201',
        ]);

        $this->fakeMetaApi('1201', [
            ['date_start' => '2026-09-22', 'spend' => '8.00', 'impressions' => '400', 'clicks' => '2'],
        ], [
            [
                'id' => 'adset-1',
                'name' => 'Primary ad set',
                'status' => 'ACTIVE',
                'effective_status' => 'ACTIVE',
                'daily_budget' => '2500',
                'learning_stage_info' => ['status' => 'LEARNING'],
                'targeting' => [
                    'geo_locations' => ['countries' => ['IT']],
                    'locales' => ['6'],
                ],
            ],
        ], [
            'id' => '1201',
            'name' => 'Italy packages live',
            'status' => 'ACTIVE',
            'effective_status' => 'ACTIVE',
            'objective' => 'OUTCOME_TRAFFIC',
            'account_id' => 'act_111',
            'daily_budget' => '3000',
        ]);

        $this->artisan('campaigns:sync-performance', ['--dump' => true])->assertSuccessful();

        $profile = CampaignPerformanceProfile::query()->first();
        $this->assertNotNull($profile);
        $this->assertSame('meta', $profile->platform);
        $this->assertSame('1201', $profile->external_campaign_id);
        $this->assertSame($campaign->id, $profile->local_campaign_id);
        $this->assertSame('Italy packages live', $profile->name);
        $this->assertSame('OUTCOME_TRAFFIC', $profile->objective);
        $this->assertSame(30.0, (float) $profile->daily_budget);
        $this->assertSame(['IT'], $profile->regions);
        $this->assertSame('LEARNING', $profile->platformLearningLabel());
        $this->assertSame('LEARNING', $profile->delivery_status);
        $this->assertNull($profile->last_error);
    }

    public function test_profile_sync_stamps_delivery_status_onto_stats_rows(): void
    {
        $user = User::factory()->create();
        $campaign = Campaign::create([
            'user_id' => $user->id,
            'name' => 'Italy packages',
            'platform' => 'meta',
            'status' => 'published',
            'budget' => 20,
            'ad_account_id' => 'act_111',
            'external_campaign_id' => '1201',
        ]);

        CampaignPerformanceStat::create([
            'user_id' => $user->id,
            'platform' => 'meta',
            'external_campaign_id' => '1201',
            'local_campaign_id' => $campaign->id,
            'stat_date' => '2026-09-22',
            'spend' => 8.00,
            'impressions' => 400,
            'clicks' => 2,
            'platform_status' => 'ACTIVE',
            'fetched_at' => now(),
        ]);

        CampaignPerformanceHourStat::create([
            'user_id' => $user->id,
            'platform' => 'meta',
            'external_campaign_id' => '1201',
            'local_campaign_id' => $campaign->id,
            'stat_hour' => '2026-09-22 11:00:00',
            'spend' => 1.00,
            'impressions' => 50,
            'clicks' => 1,
            'platform_status' => 'ACTIVE',
            'fetched_at' => now(),
        ]);

        $this->fakeMetaApi('1201', [
            ['date_start' => '2026-09-22', 'spend' => '8.00', 'impressions' => '400', 'clicks' => '2'],
        ], [
            [
                'id' => 'adset-1',
                'status' => 'ACTIVE',
                'effective_status' => 'ACTIVE',
                'learning_stage_info' => ['status' => 'LEARNING'],
                'targeting' => ['geo_locations' => ['countries' => ['IT']]],
            ],
        ], [
            'id' => '1201',
            'status' => 'ACTIVE',
            'effective_status' => 'ACTIVE',
        ]);

        $this->artisan('campaigns:sync-performance', ['--dump' => true])->assertSuccessful();

        $day = CampaignPerformanceStat::query()->first();
        $hour = CampaignPerformanceHourStat::query()->first();

        $this->assertSame('LEARNING', $day->delivery_status);
        $this->assertSame('ACTIVE', $day->platform_status);
        $this->assertSame('LEARNING', $hour->delivery_status);
    }

    public function test_profile_sync_handles_attribution_windows_as_an_array(): void
    {
        $user = User::factory()->create();
        Campaign::create([
            'user_id' => $user->id,
            'name' => 'Campaign 1201',
            'platform' => 'meta',
            'status' => 'published',
            'budget' => 20,
            'ad_account_id' => 'act_111',
            'external_campaign_id' => '1201',
        ]);

        $this->fakeMetaApi('1201', [
            ['date_start' => '2026-09-22', 'spend' => '8.00', 'impressions' => '400', 'clicks' => '2'],
        ], [
            [
                'id' => 'adset-1',
                'status' => 'ACTIVE',
                'effective_status' => 'ACTIVE',
                'learning_stage_info' => [
                    'status' => 'LEARNING',
                    'attribution_windows' => ['7d_click', '1d_view'],
                ],
                'targeting' => ['geo_locations' => ['countries' => ['IT']]],
            ],
        ], [
            'id' => '1201',
            'name' => 'Italy packages live',
            'status' => 'ACTIVE',
            'effective_status' => 'ACTIVE',
        ]);

        $this->artisan('campaigns:sync-performance', ['--dump' => true])->assertSuccessful();

        $profile = CampaignPerformanceProfile::query()->first();
        $this->assertNotNull($profile);
        $this->assertSame('Italy packages live', $profile->name);
        $this->assertSame('7d_click, 1d_view', $profile->platform_learning['detail'] ?? null);
        $this->assertNull($profile->last_error);
    }

    public function test_map_includes_campaign_profile_in_snapshot(): void
    {
        config(['campaign-performance.llm_enabled' => false]);

        $user = User::factory()->create();
        $campaign = Campaign::create([
            'user_id' => $user->id,
            'name' => 'Italy packages',
            'platform' => 'meta',
            'status' => 'published',
            'budget' => 20,
            'ad_account_id' => 'act_111',
            'external_campaign_id' => '1201',
        ]);

        CampaignPerformanceStat::create([
            'user_id' => $user->id,
            'platform' => 'meta',
            'external_campaign_id' => '1201',
            'local_campaign_id' => $campaign->id,
            'stat_date' => '2026-09-22',
            'spend' => 12.10,
            'impressions' => 800,
            'clicks' => 0,
            'platform_status' => 'ACTIVE',
            'fetched_at' => now(),
        ]);

        CampaignPerformanceProfile::create([
            'user_id' => $user->id,
            'platform' => 'meta',
            'external_campaign_id' => '1201',
            'local_campaign_id' => $campaign->id,
            'name' => 'Italy packages live',
            'objective' => 'OUTCOME_TRAFFIC',
            'daily_budget' => 30,
            'platform_status' => 'ACTIVE',
            'delivery_status' => 'LEARNING',
            'regions' => ['IT'],
            'platform_learning' => ['source' => 'meta_adset', 'status' => 'LEARNING'],
            'fetched_at' => now(),
        ]);

        Http::fake();

        $this->artisan('campaigns:sync-performance', ['--map' => true])->assertSuccessful();

        $row = CampaignPerformanceSuggestion::query()->first();
        $this->assertNotNull($row);
        $this->assertSame('Italy packages live', $row->snapshot['campaign']);
        $this->assertSame('LEARNING', $row->snapshot['delivery_status']);
        $this->assertSame('IT', $row->snapshot['campaign_profile']['region_label']);
        $this->assertSame('LEARNING', $row->snapshot['campaign_profile']['platform_learning_label']);
    }

    /**
     * @param  list<array<string, mixed>>  $days
     * @param  list<array<string, mixed>>  $adSets
     * @param  array<string, mixed>  $campaign
     */
    private function fakeMetaApi(string $campaignId, array $days, array $adSets = [], array $campaign = []): void
    {
        $campaign = array_merge([
            'id' => $campaignId,
            'name' => 'Live',
            'status' => 'PAUSED',
            'effective_status' => 'PAUSED',
        ], $campaign);

        Http::fake(function (Request $request) use ($campaignId, $days, $adSets, $campaign) {
            $url = $request->url();

            if (str_contains($url, '/insights')) {
                return Http::response(['data' => $days]);
            }

            if (str_contains($url, '/adsets')) {
                return Http::response(['data' => $adSets]);
            }

            if (str_contains($url, $campaignId)) {
                return Http::response($campaign);
            }

            return Http::response([], 404);
        });
    }
}
