<?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 — partial CRM routing
    // -------------------------------------------------------------------------

    public function test_partial_enquiry_only_runs_designated_partial_crm_action(): void
    {
        $form = Form::factory()->create([
            'data' => ['partial_crm_action' => 'send-to-enquiry-max'],
        ]);

        $enquiry = Enquiry::factory()->create([
            'form_id' => $form->id,
            'status_id' => 0,
            'ingested_at' => null,
        ]);

        $partialAction = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'send-to-enquiry-max',
            'processed_at' => null,
            'failed_at' => null,
            'attempts' => 0,
        ]);

        $otherAction = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'send-copy-via-mail',
            'processed_at' => null,
            'failed_at' => null,
            'attempts' => 0,
        ]);

        $handler = \Mockery::mock(\Mtc\Crm\Contracts\EnquiryAction::class);
        $handler->shouldReceive('handle')->once()->andReturn(true);
        $handler->shouldReceive('successDetails')->andReturn('ok');

        Enquiries::shouldReceive('makeAction')
            ->with('send-to-enquiry-max')
            ->once()
            ->andReturn($handler);

        // send-copy-via-mail should never be instantiated
        Enquiries::shouldReceive('makeAction')
            ->with('send-copy-via-mail')
            ->never();

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

        $this->assertNotNull($partialAction->fresh()->processed_at);
        $this->assertNull($otherAction->fresh()->processed_at); // untouched
    }

    public function test_full_submission_runs_all_actions_regardless_of_partial_crm_setting(): void
    {
        $form = Form::factory()->create([
            'data' => ['partial_crm_action' => 'send-to-enquiry-max'],
        ]);

        $enquiry = Enquiry::factory()->create([
            'form_id' => $form->id,
            'status_id' => 1, // full submission
            'ingested_at' => null,
        ]);

        $action1 = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'send-to-enquiry-max',
            'processed_at' => null,
            'failed_at' => null,
            'attempts' => 0,
        ]);

        $action2 = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'send-copy-via-mail',
            'processed_at' => null,
            'failed_at' => null,
            'attempts' => 0,
        ]);

        $handler = \Mockery::mock(\Mtc\Crm\Contracts\EnquiryAction::class);
        $handler->shouldReceive('handle')->twice()->andReturn(true);
        $handler->shouldReceive('successDetails')->andReturn('ok');

        Enquiries::shouldReceive('makeAction')->andReturn($handler);

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

        $this->assertNotNull($action1->fresh()->processed_at);
        $this->assertNotNull($action2->fresh()->processed_at); // both ran
    }

    public function test_partial_enquiry_runs_all_actions_when_no_partial_crm_configured(): void
    {
        $form = Form::factory()->create([
            'data' => ['partial_crm_action' => null],
        ]);

        $enquiry = Enquiry::factory()->create([
            'form_id' => $form->id,
            'status_id' => 0,
            'ingested_at' => null,
        ]);

        $action1 = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'send-to-enquiry-max',
            'processed_at' => null,
            'failed_at' => null,
            'attempts' => 0,
        ]);

        $action2 = EnquiryAction::factory()->create([
            'enquiry_id' => $enquiry->id,
            'action_name' => 'send-copy-via-mail',
            'processed_at' => null,
            'failed_at' => null,
            'attempts' => 0,
        ]);

        $handler = \Mockery::mock(\Mtc\Crm\Contracts\EnquiryAction::class);
        $handler->shouldReceive('handle')->twice()->andReturn(true);
        $handler->shouldReceive('successDetails')->andReturn('ok');

        Enquiries::shouldReceive('makeAction')->andReturn($handler);

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

        // Falls back to all actions when no partial CRM is set
        $this->assertNotNull($action1->fresh()->processed_at);
        $this->assertNotNull($action2->fresh()->processed_at);
    }

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

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