<?php

namespace Tests\Feature;

use App\Agent\Instructions;
use App\Agent\Workspace;
use App\Models\Campaign;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

/**
 * Every campaign says whether it reached its platform, not just the one in focus.
 *
 * IN THIS CONVERSATION listed a name and an id and nothing else, and CURRENTLY
 * IN FOCUS carries the full state of one campaign only. So the moment focus
 * moved, the model had no way to know what had happened to the others, and
 * answered from memory.
 *
 * Seen on arb-dev on 25 Sep:
 *
 *   06:09:05  "Approve and publish"   turn ends with the approval pending
 *   06:09:32  Meta campaign published, external id 52626656086665 assigned
 *   06:10:14  "Meta was not published because the approval step didn't
 *              complete; it remains a draft"
 *
 * Forty-two seconds. The same conversation later called a Google campaign whose
 * publish had failed a draft as well. Telling a buyer a live campaign does not
 * exist is the worst version of this: nobody goes looking for it, and it sits
 * on the account unattended.
 */
class EveryCampaignsPublishStateIsInThePromptTest extends TestCase
{
    use RefreshDatabase;

    protected Workspace $workspace;

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

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

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

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

        $this->workspace->produced($campaign, focus: false);

        return $campaign;
    }

    private function listing(): string
    {
        $text = app(Instructions::class)->build();
        $from = strpos($text, 'IN THIS CONVERSATION');

        return substr($text, $from, strpos($text, 'CURRENTLY IN FOCUS') - $from);
    }

    /** The defect: a published campaign readable while something else is in focus. */
    public function test_a_published_campaign_says_so_with_its_platform_id(): void
    {
        $this->campaign('meta', ['status' => 'published', 'external_campaign_id' => '52626656086665']);

        // Focus is elsewhere, which is the condition that broke it.
        $this->workspace->focusOn($this->campaign('google'));

        $listing = $this->listing();

        $this->assertStringContainsString('PUBLISHED on meta as 52626656086665', $listing);
    }

    /** A failed publish is not a draft, and the reason travels with it. */
    public function test_a_failed_publish_is_reported_as_failed_with_its_reason(): void
    {
        $this->campaign('google', ['status' => 'failed', 'last_error' => 'OPERATION_NOT_PERMITTED_FOR_CONTEXT']);

        $listing = $this->listing();

        $this->assertStringContainsString('publishing FAILED', $listing);
        $this->assertStringContainsString('OPERATION_NOT_PERMITTED_FOR_CONTEXT', $listing);
        $this->assertStringNotContainsString('draft, never sent to google', $listing);
    }

    /** And a draft says plainly that nothing was ever sent. */
    public function test_a_draft_says_it_never_reached_the_platform(): void
    {
        $this->campaign('linkedin');

        $this->assertStringContainsString('draft, never sent to linkedin', $this->listing());
    }

    /** Mid-publish is its own answer, because neither yes nor no is true yet. */
    public function test_a_campaign_mid_publish_is_neither_published_nor_draft(): void
    {
        $this->campaign('meta', ['status' => 'publishing']);

        $listing = $this->listing();

        $this->assertStringContainsString('publishing right now, not finished', $listing);
        $this->assertStringNotContainsString('PUBLISHED on meta', $listing);
    }

    /** Three campaigns, three different states, all readable at once. */
    public function test_every_campaign_carries_its_own_state(): void
    {
        $this->campaign('meta', ['status' => 'published', 'external_campaign_id' => '111']);
        $this->campaign('google', ['status' => 'failed', 'last_error' => 'quota exceeded']);
        $this->campaign('linkedin');

        $listing = $this->listing();

        $this->assertStringContainsString('PUBLISHED on meta as 111', $listing);
        $this->assertStringContainsString('publishing FAILED', $listing);
        $this->assertStringContainsString('draft, never sent to linkedin', $listing);
    }

    /** And the model is told to read it rather than remember. */
    public function test_the_prompt_forbids_answering_from_memory(): void
    {
        $this->campaign('meta');

        $this->assertStringContainsString(
            'Never say whether a campaign is published, failed or still a draft from memory',
            app(Instructions::class)->build(),
        );
    }
}
