<?php

namespace Tests\Feature;

use App\Agent\Workspace;
use App\Campaigns\CampaignImporter;
use App\Campaigns\LaunchFlow;
use App\Models\Campaign;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Tests\TestCase;

/**
 * A campaign that already exists keeps the declaration it was built with.
 *
 * Adoption never read the special ad category, so it stayed null, which this
 * product reads as "nobody has been asked". The flow then listed it as an
 * outstanding step on a campaign that has been live for weeks, and answering it
 * would have invited a different answer from the one Meta is holding.
 *
 * Meta writes "no category" as an empty list while null here means never asked,
 * so the two have to be told apart on the way in.
 */
class AdoptedCategoryTest extends TestCase
{
    use RefreshDatabase;

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

        config([
            'platforms.guardrails.allowed_ad_accounts' => ['act_777'],
            'platforms.meta.token' => 'test-token',
        ]);
    }

    private function adopt(array $campaignFields): Campaign
    {
        Http::fake([
            '*/adsets*' => Http::response(['data' => []]),
            '*' => Http::response(array_merge([
                'id' => '120111',
                'name' => 'Existing campaign',
                'account_id' => '777',
                'objective' => 'OUTCOME_TRAFFIC',
            ], $campaignFields)),
        ]);

        return app(CampaignImporter::class)->adopt('120111', User::factory()->create());
    }

    public function test_a_campaign_with_no_category_is_adopted_as_answered(): void
    {
        $campaign = $this->adopt(['special_ad_categories' => []]);

        $this->assertSame(['NONE'], $campaign->special_ad_categories);
    }

    public function test_a_declared_category_is_adopted_as_it_stands(): void
    {
        $campaign = $this->adopt(['special_ad_categories' => ['HOUSING']]);

        $this->assertSame(['HOUSING'], $campaign->special_ad_categories);
    }

    /**
     * The flow stops asking, which is the whole point.
     *
     * Checked through LaunchFlow rather than the column, because the symptom
     * was a live campaign showing an outstanding step.
     */
    public function test_the_flow_no_longer_asks_an_adopted_campaign_for_a_category(): void
    {
        $campaign = $this->adopt(['special_ad_categories' => []]);

        $this->assertNotSame(
            'special_ad_categories',
            app(LaunchFlow::class)->next($campaign)['key'] ?? null,
        );

        $settled = collect(app(LaunchFlow::class)->progress($campaign))
            ->firstWhere('key', 'special_ad_categories');

        $this->assertTrue($settled['done'], 'the category should be settled on an adopted campaign');
    }

    /**
     * A response without the field is the one real unknown.
     *
     * Left null so the flow still asks, rather than inventing a declaration
     * with legal weight from a field that was never returned.
     */
    public function test_a_missing_field_is_left_unanswered(): void
    {
        $campaign = $this->adopt([]);

        $this->assertNull($campaign->special_ad_categories);

        $settled = collect(app(LaunchFlow::class)->progress($campaign))
            ->firstWhere('key', 'special_ad_categories');

        $this->assertFalse($settled['done']);
    }

    /**
     * An adopted campaign says where its values came from.
     *
     * Nothing was recorded at all, so every row showed the grey dot the panel
     * uses for "not set" beside a real value read from Meta. The dots separate
     * what a person chose from what was guessed, and adoption is the case where
     * neither applies: the platform is the source and there is a colour for it.
     */
    public function test_adopted_values_are_recorded_as_coming_from_the_platform(): void
    {
        $campaign = $this->adopt([
            'special_ad_categories' => ['HOUSING'],
            'objective' => 'OUTCOME_LEADS',
            'name' => 'Someone elses campaign',
        ]);

        $sources = app(Workspace::class)->sourcesFor($campaign);

        $this->assertSame('platform_returned', $sources['objective'] ?? null);
        $this->assertSame('platform_returned', $sources['special_ad_categories'] ?? null);
        $this->assertSame('platform_returned', $sources['name'] ?? null);
    }

    /** A field Meta returned nothing for is still unanswered, not attributed. */
    public function test_a_field_meta_did_not_return_gets_no_source(): void
    {
        $campaign = $this->adopt(['special_ad_categories' => []]);

        $this->assertArrayNotHasKey('pixel_id', app(Workspace::class)->sourcesFor($campaign));
    }

    /** The read has to ask Meta for the field, or it can never arrive. */
    public function test_the_campaign_read_requests_the_declaration(): void
    {
        $this->adopt(['special_ad_categories' => []]);

        Http::assertSent(fn ($request): bool => str_contains($request->url(), 'special_ad_categories'));
    }
}
