<?php

namespace Tests\Feature;

use App\Agent\Tools\Campaign\SetTargeting;
use App\Agent\Workspace;
use App\Campaigns\LaunchFlow;
use App\Campaigns\Platforms\Platforms;
use App\Models\Campaign;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Ai\Tools\Request;
use Tests\TestCase;

/**
 * A placement belongs to a platform, not to every campaign.
 *
 * Found in the browser on 21 Sep: with a Meta and a Google campaign on one
 * brief, answering the grouped questions while Google was in focus wrote
 * placements ["facebook"] to the Google campaign. set_targeting validated the
 * answer against Objectives::PLACEMENTS, which is Meta's hardcoded list, rather
 * than against the platform the campaign actually runs on.
 *
 * Nothing caught it because until multi-platform there was only ever one
 * platform, and the constant was right by definition.
 */
class PlacementsMatchThePlatformTest extends TestCase
{
    use RefreshDatabase;

    private function campaignOn(string $platform): Campaign
    {
        $user = User::factory()->create();
        $campaign = Campaign::create([
            'user_id' => $user->id,
            'name' => 'Test',
            'platform' => $platform,
            'status' => 'draft',
        ]);

        $this->actingAs($user);
        app(Workspace::class)->focusOn($campaign);

        return $campaign;
    }

    private function setTargeting(array $arguments): string
    {
        return (string) app(SetTargeting::class)->handle(new Request($arguments));
    }

    /** A Meta placement must not land on a Google campaign. */
    public function test_a_meta_placement_is_refused_on_a_google_campaign(): void
    {
        $campaign = $this->campaignOn('google');

        $result = json_decode($this->setTargeting([
            'countries' => ['US'],
            'placements' => ['facebook'],
        ]), true);

        $this->assertFalse($result['ok'], 'Google took a Facebook placement.');
        $this->assertEmpty($campaign->fresh()->placements ?? []);
    }

    /** Google's own networks are accepted, which is what makes the refusal above a filter. */
    public function test_a_google_network_is_accepted_on_a_google_campaign(): void
    {
        $campaign = $this->campaignOn('google');

        $result = json_decode($this->setTargeting([
            'countries' => ['US'],
            'placements' => ['search'],
        ]), true);

        $this->assertTrue($result['ok']);
        $this->assertSame(['search'], $campaign->fresh()->placements);
    }

    /** The same answer is still correct on the platform it belongs to. */
    public function test_a_meta_placement_is_accepted_on_a_meta_campaign(): void
    {
        $campaign = $this->campaignOn('meta');

        $result = json_decode($this->setTargeting([
            'countries' => ['US'],
            'placements' => ['facebook'],
        ]), true);

        $this->assertTrue($result['ok']);
        $this->assertSame(['facebook'], $campaign->fresh()->placements);
    }

    /**
     * A platform with no placements still finishes its targeting step.
     *
     * Otherwise the fix above trades a wrong value for a deadlock: done()
     * required a placement, so a platform that has none would sit on "countries
     * and placements" for the rest of the conversation.
     *
     * Taboola rather than Google: Google declares its four networks now that it
     * has real rules, so it is no longer an example of a platform with none.
     * Every platform still on UnsupportedPlatformRules is.
     */
    public function test_targeting_completes_on_a_platform_that_has_no_placements(): void
    {
        $campaign = $this->campaignOn('taboola');

        $this->assertSame([], app(Platforms::class)->for($campaign)->placements());

        $this->setTargeting(['countries' => ['US']]);

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

        $this->assertTrue($progress['done'], 'A platform with no placements can never finish targeting.');
    }

    /** Meta still has to answer placements, which is what makes the above safe. */
    public function test_targeting_is_not_complete_on_meta_without_placements(): void
    {
        $campaign = $this->campaignOn('meta');

        $this->setTargeting(['countries' => ['US']]);

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

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