<?php

namespace Tests\Tenant;

use App\Jobs\ProcessIncomingEnquiryJob;
use Carbon\Carbon;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Bus;
use Mtc\Crm\Facades\Enquiries;
use Mtc\Crm\Models\Enquiry;
use Mtc\Crm\Models\EnquiryAction;
use Mtc\Crm\Models\FormQuestion;
use Mtc\Crm\Models\FormSection;
use Mtc\MercuryDataModels\Form;
use Tests\TenantTestCase;

class PartialSubmissionsTest extends TenantTestCase
{
    // -------------------------------------------------------------------------
    // IngestEnquiries — hasSufficientDraftData
    // -------------------------------------------------------------------------

    public function test_partial_enquiry_is_dispatched_when_draft_field_is_populated(): void
    {
        Bus::fake();

        $form = Form::factory()->create(['data' => ['partial_submissions' => true]]);
        $section = FormSection::factory()->create(['form_id' => $form->id]);
        $question = FormQuestion::factory()->create([
            'form_id' => $form->id,
            'form_section_id' => $section->id,
            'data' => ['include_in_draft' => true],
        ]);

        $enquiry = Enquiry::factory()->create([
            'form_id' => $form->id,
            'status_id' => 0,
            'ingested_at' => null,
            'updated_at' => Carbon::now()->subMinutes(10),
            'details' => [$question->id => 'John'],
        ]);

        $this->setSetting('crm-ingest-partial-submissions-minutes', 5);

        Artisan::call('enquiries:ingest');

        Bus::assertDispatched(ProcessIncomingEnquiryJob::class);
    }

    public function test_partial_enquiry_is_skipped_when_no_draft_fields_are_populated(): void
    {
        Bus::fake();

        $form = Form::factory()->create(['data' => ['partial_submissions' => true]]);
        $section = FormSection::factory()->create(['form_id' => $form->id]);
        FormQuestion::factory()->create([
            'form_id' => $form->id,
            'form_section_id' => $section->id,
            'data' => ['include_in_draft' => true],
        ]);

        Enquiry::factory()->create([
            'form_id' => $form->id,
            'status_id' => 0,
            'ingested_at' => null,
            'updated_at' => Carbon::now()->subMinutes(10),
            'details' => [], // nothing filled in
        ]);

        $this->setSetting('crm-ingest-partial-submissions-minutes', 5);

        Artisan::call('enquiries:ingest');

        Bus::assertNotDispatched(ProcessIncomingEnquiryJob::class);
    }

    public function test_partial_enquiry_is_skipped_when_form_has_no_draft_questions(): void
    {
        Bus::fake();

        $form = Form::factory()->create(['data' => ['partial_submissions' => true]]);
        $section = FormSection::factory()->create(['form_id' => $form->id]);
        // Question exists but include_in_draft is not set
        FormQuestion::factory()->create([
            'form_id' => $form->id,
            'form_section_id' => $section->id,
            'data' => [],
        ]);

        Enquiry::factory()->create([
            'form_id' => $form->id,
            'status_id' => 0,
            'ingested_at' => null,
            'updated_at' => Carbon::now()->subMinutes(10),
            'details' => ['some' => 'data'],
        ]);

        $this->setSetting('crm-ingest-partial-submissions-minutes', 5);

        Artisan::call('enquiries:ingest');

        Bus::assertNotDispatched(ProcessIncomingEnquiryJob::class);
    }

    public function test_full_submission_always_passes_sufficient_data_check(): void
    {
        Bus::fake();

        // Full enquiry with no form attached — should still be dispatched
        Enquiry::factory()->create([
            'form_id' => null,
            'status_id' => 1,
            'ingested_at' => null,
            'details' => [],
        ]);

        $this->setSetting('crm-ingest-partial-submissions-minutes', 5);

        Artisan::call('enquiries:ingest');

        Bus::assertDispatched(ProcessIncomingEnquiryJob::class);
    }

    public function test_partial_enquiry_is_not_dispatched_before_inactivity_window(): void
    {
        Bus::fake();

        $form = Form::factory()->create(['data' => ['partial_submissions' => true]]);
        $section = FormSection::factory()->create(['form_id' => $form->id]);
        $question = FormQuestion::factory()->create([
            'form_id' => $form->id,
            'form_section_id' => $section->id,
            'data' => ['include_in_draft' => true],
        ]);

        Enquiry::factory()->create([
            'form_id' => $form->id,
            'status_id' => 0,
            'ingested_at' => null,
            'updated_at' => Carbon::now()->subMinutes(2), // only 2 mins ago
            'details' => [$question->id => 'John'],
        ]);

        $this->setSetting('crm-ingest-partial-submissions-minutes', 5); // window is 5 mins

        Artisan::call('enquiries:ingest');

        Bus::assertNotDispatched(ProcessIncomingEnquiryJob::class);
    }

    // -------------------------------------------------------------------------
    // ProcessIncomingEnquiryJob — per-action trigger routing
    // -------------------------------------------------------------------------

    public function test_partial_only_action_fires_for_partial_enquiry(): void
    {
        $enquiry = Enquiry::factory()->create(['status_id' => 0, 'ingested_at' => null]);

        $partialAction = $this->createAction($enquiry->id, 'send-copy-via-mail', 'partial');
        $fullAction = $this->createAction($enquiry->id, 'send-to-salesforce', 'full');
        $allAction = $this->createAction($enquiry->id, 'send-to-enquiry-max', 'all');

        $this->expectActionsFired(['send-copy-via-mail', 'send-to-enquiry-max']);

        (new ProcessIncomingEnquiryJob($enquiry))->handle();

        $this->assertNotNull($partialAction->fresh()->processed_at);
        $this->assertNull($fullAction->fresh()->processed_at); // skipped
        $this->assertNotNull($allAction->fresh()->processed_at);
    }

    public function test_full_only_action_fires_for_full_submission(): void
    {
        $enquiry = Enquiry::factory()->create(['status_id' => 1, 'ingested_at' => null]);

        $partialAction = $this->createAction($enquiry->id, 'send-copy-via-mail', 'partial');
        $fullAction = $this->createAction($enquiry->id, 'send-to-salesforce', 'full');
        $allAction = $this->createAction($enquiry->id, 'send-to-enquiry-max', 'all');

        $this->expectActionsFired(['send-to-salesforce', 'send-to-enquiry-max']);

        (new ProcessIncomingEnquiryJob($enquiry))->handle();

        $this->assertNull($partialAction->fresh()->processed_at); // skipped
        $this->assertNotNull($fullAction->fresh()->processed_at);
        $this->assertNotNull($allAction->fresh()->processed_at);
    }

    public function test_action_without_trigger_defaults_to_all(): void
    {
        $enquiry = Enquiry::factory()->create(['status_id' => 0, 'ingested_at' => null]);

        // No trigger key in fields — should default to 'all'
        $action = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'send-copy-via-mail',
            'data' => [],
            'processed_at' => null,
            'failed_at' => null,
            'attempts' => 0,
        ]);

        $this->expectActionsFired(['send-copy-via-mail']);

        (new ProcessIncomingEnquiryJob($enquiry))->handle();

        $this->assertNotNull($action->fresh()->processed_at);
    }

    // -------------------------------------------------------------------------
    // Helpers
    // -------------------------------------------------------------------------

    private function setSetting(string $key, mixed $value): void
    {
        \App\Facades\Settings::update($key, $value);
    }

    private function createAction(int $enquiryId, string $actionName, string $trigger): EnquiryAction
    {
        return EnquiryAction::factory()->create([
            'enquiry_id' => $enquiryId,
            'action_name' => $actionName,
            'data' => ['trigger' => $trigger],
            'processed_at' => null,
            'failed_at' => null,
            'attempts' => 0,
        ]);
    }

    private function expectActionsFired(array $actionNames): void
    {
        $handler = \Mockery::mock(\Mtc\Crm\Contracts\EnquiryAction::class);
        $handler->shouldReceive('handle')->times(count($actionNames))->andReturn(true);
        $handler->shouldReceive('successDetails')->andReturn('ok');

        foreach ($actionNames as $name) {
            Enquiries::shouldReceive('makeAction')->with($name)->andReturn($handler);
        }
    }
}
