<?php

namespace Tests\Feature;

use App\Agent\Choices;
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;

/**
 * What happens when no Page matches the brand.
 *
 * Matching on the landing page is the good case and is covered by
 * SuggestionTest. This is the other half: a brand with no Page of its own, and
 * an ad account with no Page at all.
 *
 * Neither had an answer. Nothing was badged, which is right, but nothing said
 * why either, so fifty Pages were presented as though one of them were plainly
 * correct. And with no Pages at all, Choices::offer() ignored the empty list
 * while the tool still reported ok and told the model the Pages were on screen,
 * so the model said its line and waited for a click that could never come.
 *
 * The fallback is evidence, never a guess: a Page another campaign in this
 * conversation already posts as. The ad account's name is not coming back as a
 * hint, which is what badged MidoWeb's Pages for attestpath.ai.
 */
class PageFallbackTest extends TestCase
{
    use RefreshDatabase;

    protected Workspace $workspace;

    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());

        $this->workspace = app(Workspace::class);
        $this->workspace->bindTo('conv-page-fallback');
    }

    private function campaign(string $name, array $attributes = []): Campaign
    {
        $campaign = Campaign::create([
            'user_id' => auth()->id(),
            'name' => $name,
            'platform' => 'meta',
            'status' => 'draft',
            'ad_account_id' => 'act_777',
            ...$attributes,
        ]);

        $this->workspace->produced($campaign);

        return $campaign;
    }

    /** @param list<array<string,mixed>> $pages */
    private function listPages(array $pages): array
    {
        Http::fake([
            '*/me/accounts*' => Http::response(['data' => $pages]),
            '*/act_777*' => Http::response(['id' => 'act_777', 'name' => 'MidoWeb-WWBlog', 'account_status' => 1]),
            '*' => Http::response(['data' => []]),
        ]);

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

        return [
            json_decode((string) $result, true),
            collect(app(Choices::class)->all())->firstWhere('field', 'page_id'),
        ];
    }

    /** An account with no Page is a blocker, and has to be said as one. */
    public function test_an_account_with_no_pages_refuses_instead_of_asking(): void
    {
        $this->campaign('Winter Sale', ['landing_url' => 'https://attestpath.ai/']);

        [$result, $choice] = $this->listPages([]);

        $this->assertFalse($result['ok'], 'Reported success while the screen stayed empty.');
        $this->assertNull($choice);
        $this->assertStringContainsString('no Facebook Page', $result['error']);
        $this->assertStringContainsString('Meta Business Suite', $result['note']);
    }

    /** No match is still every Page, but the model is told nothing matched. */
    public function test_nothing_matching_is_said_rather_than_left_unexplained(): void
    {
        $this->campaign('Winter Sale', ['landing_url' => 'https://attestpath.ai/']);

        [$result, $choice] = $this->listPages([
            ['id' => '1', 'name' => 'MidoWeb', 'category' => 'Software'],
            ['id' => '2', 'name' => 'WWBlog Hub', 'category' => 'Media'],
        ]);

        $this->assertTrue($result['ok']);
        $this->assertCount(2, $choice['options'], 'Every Page should still be reachable.');
        $this->assertSame([], array_filter(array_column($choice['options'], 'badge')), 'Another brand was suggested.');
        $this->assertArrayHasKey('nothing_matched', $result);
    }

    /**
     * The fallback: a Page the buyer already chose in this conversation.
     *
     * attestpath.ai matches neither Page name, but one of them is what the
     * other campaign in this chat publishes as, and that is a decision the
     * buyer made rather than a name that happens to be nearby.
     */
    public function test_a_page_used_by_another_campaign_here_is_offered_first(): void
    {
        $this->campaign('Attest Meta', ['landing_url' => 'https://attestpath.ai/', 'page_id' => '2']);
        $this->campaign('Attest Second', ['landing_url' => 'https://attestpath.ai/']);

        [$result, $choice] = $this->listPages([
            ['id' => '1', 'name' => 'MidoWeb', 'category' => 'Software'],
            ['id' => '2', 'name' => 'WWBlog Hub', 'category' => 'Media'],
        ]);

        $this->assertSame('2', $choice['options'][0]['value']);
        $this->assertSame('Suggested', $choice['options'][0]['badge']);
        $this->assertStringContainsString('Another campaign in this chat', $choice['options'][0]['hint']);
        $this->assertArrayNotHasKey('nothing_matched', $result);
    }

    /** And it stays a reordering: the others are all still there. */
    public function test_the_other_pages_remain_reachable_behind_the_fallback(): void
    {
        $this->campaign('Attest Meta', ['landing_url' => 'https://attestpath.ai/', 'page_id' => '2']);
        $this->campaign('Attest Second', ['landing_url' => 'https://attestpath.ai/']);

        [, $choice] = $this->listPages([
            ['id' => '1', 'name' => 'MidoWeb', 'category' => 'Software'],
            ['id' => '2', 'name' => 'WWBlog Hub', 'category' => 'Media'],
        ]);

        $this->assertCount(2, $choice['options']);
        $this->assertContains('1', array_column($choice['options'], 'value'));
    }

    /** A real brand match still wins over the fallback. */
    public function test_the_brand_match_beats_the_page_used_elsewhere(): void
    {
        $this->campaign('Other', ['landing_url' => 'https://stockprices.com/', 'page_id' => '1']);
        $this->campaign('Winter Sale', ['landing_url' => 'https://stockprices.com/']);

        [, $choice] = $this->listPages([
            ['id' => '1', 'name' => 'MidoWeb', 'category' => 'Software'],
            ['id' => '2', 'name' => 'Stockprices.com', 'category' => 'Finance'],
        ]);

        $this->assertSame('2', $choice['options'][0]['value'], 'The brand match should outrank the earlier pick.');
    }
}
