<?php

namespace Tests\Feature;

use App\Agent\ToolRegistry;
use App\Agent\Workspace;
use App\Models\Campaign;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Http;
use Laravel\Ai\Tools\Request;
use Tests\TestCase;

/**
 * Publishing as a brand that is not the one being advertised is said out loud.
 *
 * Suggesting the wrong Page was fixed by suggesting none when nothing matches.
 * That left the other half: the buyer can still pick any Page on the account,
 * and every ad then carries that brand's name.
 *
 * Seen on arb-dev twice on 25 Sep. attestpath.ai and webcrawlers.com were both
 * set to publish as "Stockprices.com", each immediately after the product had
 * said no Page matched, and neither was questioned. One of them reached Meta.
 *
 * Not refused. One ad account legitimately runs several brands and the buyer
 * knows which Page is theirs. But it is worth a sentence before it goes out,
 * because afterwards it is somebody else's name on the ad.
 */
class APageForAnotherBrandIsFlaggedTest extends TestCase
{
    use RefreshDatabase;

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

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

        $this->actingAs(User::factory()->create());

        app(Workspace::class)->bindTo('conv-brand-mismatch');
    }

    private function choose(string $landingUrl, string $pageId): array
    {
        $campaign = Campaign::create([
            'user_id' => auth()->id(),
            'name' => 'Winter Sale',
            'platform' => 'meta',
            'status' => 'draft',
            'ad_account_id' => 'act_777',
            'landing_url' => $landingUrl,
        ]);

        app(Workspace::class)->produced($campaign);

        Http::fake([
            '*/me/accounts*' => Http::response(['data' => [
                ['id' => '1007341679135585', 'name' => 'Stockprices.com', 'category' => 'Finance'],
                ['id' => '2', 'name' => 'AttestPath', 'category' => 'Software'],
            ]]),
            '*/act_777*' => Http::response(['id' => 'act_777', 'name' => 'Main', 'account_status' => 1]),
            '*' => Http::response(['data' => []]),
        ]);

        $result = collect(app(ToolRegistry::class)->resolve())
            ->first(fn ($t) => $t->name() === 'campaign__choose_page')
            ->handle(new Request(['page_id' => $pageId]));

        return json_decode((string) $result, true);
    }

    /** The exact case from arb-dev, twice. */
    public function test_a_page_for_another_brand_is_flagged(): void
    {
        $result = $this->choose('https://attestpath.ai/', '1007341679135585');

        $this->assertTrue($result['ok'], 'It is a warning, not a refusal.');
        $this->assertArrayHasKey('brand_mismatch', $result);
        $this->assertStringContainsString('Stockprices.com', $result['brand_mismatch']);
        $this->assertStringContainsString('attestpath.ai', $result['brand_mismatch']);
    }

    /** And the model is told to get it confirmed rather than mention it in passing. */
    public function test_the_model_is_told_to_ask_for_confirmation(): void
    {
        $result = $this->choose('https://attestpath.ai/', '1007341679135585');

        $this->assertStringContainsString('carry its name', $result['note']);
        $this->assertStringContainsString('change the Page', $result['note']);
    }

    /**
     * Said once, not appended to every later answer.
     *
     * The note used to read "ask them to confirm before publishing", and the
     * model obeyed it literally: Mohsin was asked whether The-Answer-Hub was
     * the intended Page seven times in one conversation, tacked onto replies
     * about bidding, targeting, the schedule and creatives, because he never
     * treated it as a question and so never answered it.
     */
    public function test_the_model_is_told_not_to_keep_asking(): void
    {
        $note = $this->choose('https://attestpath.ai/', '1007341679135585')['note'];

        $this->assertStringContainsString('once', $note);
        $this->assertStringContainsString('Do not ask again', $note);
        $this->assertStringNotContainsString('confirm before publishing', $note);
    }

    /** The Page is still set, because the buyer may well be right. */
    public function test_the_page_is_still_set(): void
    {
        $this->choose('https://attestpath.ai/', '1007341679135585');

        $this->assertSame('1007341679135585', Campaign::sole()->page_id);
    }

    /** A Page that matches the brand says nothing at all. */
    public function test_a_matching_page_is_not_flagged(): void
    {
        $result = $this->choose('https://attestpath.ai/', '2');

        $this->assertTrue($result['ok']);
        $this->assertArrayNotHasKey('brand_mismatch', $result);
    }

    /**
     * No landing page means no evidence either way, and no evidence is not a
     * mismatch. Warning on every Page would teach people to ignore it.
     */
    public function test_nothing_is_said_when_there_is_no_landing_page_to_compare(): void
    {
        $result = $this->choose('', '1007341679135585');

        $this->assertTrue($result['ok']);
        $this->assertArrayNotHasKey('brand_mismatch', $result);
    }
}
