<?php

namespace Tests\Feature;

use App\Agent\Choices;
use App\Agent\Workspace;
use App\Http\Controllers\ChatController;
use App\Models\Campaign;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use ReflectionMethod;
use Tests\TestCase;

/**
 * A clicked answer applies to the campaign its question was about.
 *
 * Tools act on whatever is in focus, and focus moves: on a multi-platform brief
 * the model calls switch_focus inside a single turn as a matter of course. So a
 * question offered about the Meta campaign was answered a turn later, by which
 * point focus had moved to Google, and the answer was applied there or refused.
 *
 * Koushik hit it on 26 Sep. He chose a special ad category, the turn ran
 * declare_ad_category, switch_focus, declare_ad_category, and he was told: "The
 * category selection didn't apply because focus had shifted. Choose it again
 * for the Meta campaign." He had chosen it once already.
 *
 * The offer now carries what was in focus when it was made, and the answer
 * borrows that focus and hands it straight back - answering a question about
 * one campaign is not a decision to start working on it.
 */
class AnAnswerLandsOnTheCampaignItWasAskedAboutTest extends TestCase
{
    use RefreshDatabase;

    private Campaign $meta;

    private Campaign $google;

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

        $this->actingAs(User::factory()->create());
        app(Workspace::class)->bindTo('conv-focus-shift');

        $this->meta = Campaign::create([
            'user_id' => auth()->id(), 'name' => 'Meta campaign',
            'platform' => 'meta', 'status' => 'draft',
        ]);

        $this->google = Campaign::create([
            'user_id' => auth()->id(), 'name' => 'Google campaign',
            'platform' => 'google', 'status' => 'draft',
        ]);

        app(Workspace::class)->produced($this->meta);
        app(Workspace::class)->produced($this->google);
    }

    private function applyAnswers(array $answers): void
    {
        $method = new ReflectionMethod(ChatController::class, 'applyAnswers');
        $method->setAccessible(true);
        $method->invoke(app(ChatController::class), $answers);
    }

    /** The defect: the answer followed the focus rather than the question. */
    public function test_an_answer_offered_for_one_campaign_is_not_applied_to_another(): void
    {
        $workspace = app(Workspace::class);

        // Offered while the Meta campaign is in focus.
        $workspace->focusOn($this->meta);
        app(Choices::class)->offer(
            field: 'special_ad_categories',
            question: 'Does this fall into a special ad category?',
            options: [['value' => 'NONE', 'label' => 'None of these']],
        );
        $workspace->rememberChoices(app(Choices::class)->all());

        // The model moves on to Google before the answer arrives.
        $workspace->focusOn($this->google);

        $this->applyAnswers([['field' => 'special_ad_categories', 'value' => 'NONE']]);

        $this->assertNotNull(
            $this->meta->refresh()->special_ad_categories,
            'the answer never reached the campaign it was asked about',
        );
        $this->assertNull(
            $this->google->refresh()->special_ad_categories,
            'the answer was applied to the campaign that happened to be in focus',
        );
    }

    /**
     * And the focus is handed back.
     *
     * Answering a question about one campaign is not a decision to start
     * working on it, so what the buyer types next must still go where they left
     * off.
     */
    public function test_the_focus_is_restored_afterwards(): void
    {
        $workspace = app(Workspace::class);

        $workspace->focusOn($this->meta);
        app(Choices::class)->offer(
            field: 'special_ad_categories',
            question: 'Does this fall into a special ad category?',
            options: [['value' => 'NONE', 'label' => 'None of these']],
        );
        $workspace->rememberChoices(app(Choices::class)->all());

        $workspace->focusOn($this->google);

        $this->applyAnswers([['field' => 'special_ad_categories', 'value' => 'NONE']]);

        $this->assertTrue(
            $this->google->is($workspace->focus()),
            'the focus was left on the campaign the answer was applied to',
        );
    }

    /** With focus where it was offered, nothing changes. */
    public function test_an_answer_with_focus_unmoved_still_applies(): void
    {
        $workspace = app(Workspace::class);

        $workspace->focusOn($this->meta);
        app(Choices::class)->offer(
            field: 'special_ad_categories',
            question: 'Does this fall into a special ad category?',
            options: [['value' => 'NONE', 'label' => 'None of these']],
        );
        $workspace->rememberChoices(app(Choices::class)->all());

        $this->applyAnswers([['field' => 'special_ad_categories', 'value' => 'NONE']]);

        $this->assertNotNull($this->meta->refresh()->special_ad_categories);
        $this->assertTrue($this->meta->is($workspace->focus()));
    }

    /** An offer made before anything was in focus is still applied. */
    public function test_an_unstamped_offer_falls_back_to_the_current_focus(): void
    {
        $workspace = app(Workspace::class);

        $workspace->focusOn($this->meta);
        $workspace->rememberChoices([[
            'field' => 'special_ad_categories',
            'question' => 'Does this fall into a special ad category?',
            'options' => [['value' => 'NONE', 'label' => 'None of these', 'sends' => 'None']],
        ]]);

        $this->applyAnswers([['field' => 'special_ad_categories', 'value' => 'NONE']]);

        $this->assertNotNull($this->meta->refresh()->special_ad_categories);
    }
}
