<?php

namespace Tests\Feature;

use App\Models\ApplicationDelivery;
use App\Models\ApplicationOutput;
use App\Models\ApprovalRequest;
use App\Models\Customer;
use App\Models\CustomerContact;
use App\Models\DocumentType;
use App\Models\Service;
use App\Models\ServiceDocumentRule;
use App\Models\Tenant;
use App\Models\User;
use App\Models\WorkflowStage;
use App\Services\ApplicationService;
use App\Services\ApplicationWorkflowProcessingService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Validation\ValidationException;
use Tests\TestCase;

class UaeTypingCenterWorkflowTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();
        $this->seed();
    }

    public function test_new_service_receives_the_standard_uae_workflow_automatically(): void
    {
        $owner = User::where('email', 'owner@almadina.ae')->firstOrFail();
        $response = $this->actingAs($owner)->post(route('app.settings.services.store'), [
            'service_code' => 'ICP-TEST-SERVICE',
            'name_en' => 'Configured Government Service',
            'gov_fee' => 0,
            'typing_fee' => 50,
            'service_charge' => 25,
            'vat_applicable' => 1,
        ]);

        $service = Service::where('service_code', 'ICP-TEST-SERVICE')->firstOrFail();
        $response->assertRedirect(route('app.services.show', $service->id));
        $this->assertSame(15, $service->workflowStages()->count());
        $this->assertSame(15, $service->workflowTransitions()->count());
        $this->assertDatabaseHas('workflow_stages', [
            'service_id' => $service->id, 'stage_code' => 'DOCUMENT_CHECK', 'requires_documents' => true,
        ]);
        $this->assertDatabaseHas('workflow_stages', [
            'service_id' => $service->id, 'stage_code' => 'PAYMENT_PENDING', 'requires_payment' => true,
        ]);
    }

    public function test_complete_uae_walk_in_return_resubmission_and_delivery_flow(): void
    {
        $tenant = Tenant::where('slug', 'al-madina-typing')->firstOrFail();
        $receptionist = User::where('email', 'reception@almadina.ae')->firstOrFail();
        $cashier = User::where('email', 'cashier@almadina.ae')->firstOrFail();
        $typist = User::where('email', 'typist@almadina.ae')->firstOrFail();
        $supervisor = User::where('email', 'supervisor@almadina.ae')->firstOrFail();
        $pro = User::where('email', 'pro@almadina.ae')->firstOrFail();
        $owner = User::where('email', 'owner@almadina.ae')->firstOrFail();

        $customer = Customer::create([
            'tenant_id' => $tenant->id, 'customer_code' => 'CUS-UAT-001',
            'first_name' => 'Ahmed', 'last_name' => 'Ali', 'full_name_en' => 'Ahmed Ali', 'status' => 'active',
        ]);
        CustomerContact::create([
            'tenant_id' => $tenant->id, 'customer_id' => $customer->id,
            'primary_mobile' => '+971501234567', 'normalized_mobile' => '971501234567',
            'whatsapp_number' => '+971501234567', 'notification_consent' => true,
        ]);
        $service = Service::create([
            'tenant_id' => $tenant->id, 'service_code' => 'UAT-VISA-RENEW',
            'name_en' => 'Residence Visa Renewal', 'gov_fee' => 500, 'typing_fee' => 50,
            'service_charge' => 25, 'vat_applicable' => true, 'vat_amount' => 3.75,
            'total_price' => 578.75, 'status' => 'active',
        ]);
        $passport = DocumentType::create([
            'tenant_id' => $tenant->id, 'name_en' => 'Passport', 'code' => 'PASSPORT',
            'entity_type' => 'customer', 'is_active' => true,
        ]);
        ServiceDocumentRule::create([
            'tenant_id' => $tenant->id, 'service_id' => $service->id,
            'document_type_id' => $passport->id, 'display_name' => 'Valid Passport Copy',
            'is_mandatory' => true, 'source_entity' => 'applicant', 'display_order' => 1,
        ]);

        $application = app(ApplicationService::class)->createApplication(
            $tenant, $customer, $service, ['branch_id' => $receptionist->default_branch_id], $receptionist
        );
        $workflow = app(ApplicationWorkflowProcessingService::class);

        $this->assertSame('INTAKE', $application->currentStage->stage_code);
        $this->assertSame($receptionist->id, $application->attended_by);
        $this->actingAs($owner)->get(route('app.applications.show', $application->id))
            ->assertOk()->assertSee('UAE Application Lifecycle')->assertSee('Customer Intake');
        $this->move($workflow, $application, 'DOCUMENT_CHECK', $receptionist);

        try {
            $this->move($workflow, $application, 'PAYMENT_PENDING', $receptionist);
            $this->fail('Document gate did not block an unverified mandatory document.');
        } catch (ValidationException $exception) {
            $this->assertStringContainsString('mandatory document', implode(' ', $exception->errors()['workflow']));
        }

        $document = $application->documents()->firstOrFail();
        $document->update([
            'attachment_path' => 'tests/passport.pdf', 'status' => 'verified',
            'verified_by' => $receptionist->id, 'verified_at' => now(),
        ]);
        $application->update(['document_status' => 'verified']);
        $this->move($workflow, $application, 'PAYMENT_PENDING', $receptionist);

        try {
            $this->move($workflow, $application, 'TYPING_QUEUE', $cashier);
            $this->fail('Payment gate did not block an unpaid application.');
        } catch (ValidationException $exception) {
            $this->assertStringContainsString('payment', strtolower(implode(' ', $exception->errors()['workflow'])));
        }

        $application->update(['payment_status' => 'paid']);
        $this->processToGovernment($workflow, $application, $cashier, $typist, $supervisor, $pro);
        $workflow->recordSubmission($application->fresh(['currentStage', 'tenant']), $pro, [
            'authority_code' => 'GDRFA', 'portal_name' => 'GDRFA Portal',
            'government_reference' => 'GOV-ATTEMPT-001', 'request_number' => 'REQ-001',
        ]);
        $this->assertSame('GOVERNMENT_PROCESSING', $application->fresh()->currentStage->stage_code);

        $workflow->recordReturn($application->fresh(['currentStage', 'tenant']), $pro, 'Updated photograph required');
        $this->assertSame('GOVERNMENT_RETURNED', $application->fresh()->currentStage->stage_code);
        $this->move($workflow, $application, 'DOCUMENT_CHECK', $typist);
        $this->move($workflow, $application, 'PAYMENT_PENDING', $receptionist);
        $this->processToGovernment($workflow, $application, $cashier, $typist, $supervisor, $pro);

        $workflow->recordSubmission($application->fresh(['currentStage', 'tenant']), $pro, [
            'authority_code' => 'GDRFA', 'portal_name' => 'GDRFA Portal',
            'government_reference' => 'GOV-ATTEMPT-002', 'request_number' => 'REQ-002',
        ]);
        $workflow->recordGovernmentDecision($application->fresh(['currentStage', 'tenant']), $supervisor, 'approved', 'Approval received');
        $this->assertSame('GOVERNMENT_APPROVED', $application->fresh()->currentStage->stage_code);

        $this->move($workflow, $application, 'OUTPUT_READY', $supervisor);
        ApplicationOutput::create([
            'tenant_id' => $tenant->id, 'application_id' => $application->id,
            'document_name' => 'Approved Residence Visa', 'output_type' => 'visa',
            'reference_number' => 'VISA-001', 'attachment_path' => 'tests/visa.pdf',
            'status' => 'ready', 'customer_visible' => true, 'uploaded_by' => $typist->id,
        ]);
        $application->update(['output_status' => 'ready']);
        $this->move($workflow, $application, 'CUSTOMER_NOTIFICATION', $typist);
        $application->update(['customer_notified_at' => now()]);
        ApplicationDelivery::create([
            'tenant_id' => $tenant->id, 'application_id' => $application->id,
            'delivery_method' => 'counter_collection', 'recipient_name' => 'Ahmed Ali',
            'recipient_mobile' => '+971501234567', 'acknowledgement' => 'Original output received.',
            'delivered_by' => $owner->id, 'delivered_at' => now(),
        ]);
        $this->move($workflow, $application, 'DELIVERED', $owner);

        $final = $application->fresh();
        $this->assertSame('delivered', $final->status);
        $this->assertSame($typist->id, $final->typed_by);
        $this->assertNotNull($final->typing_started_at);
        $this->assertNotNull($final->typing_completed_at);
        $this->assertNotNull($final->completed_at);
        $this->assertCount(2, $final->submissions);
        $this->assertSame('returned', $final->submissions()->orderBy('attempt_number')->first()->status);
        $this->assertSame('approved', $final->submissions()->orderByDesc('attempt_number')->first()->status);
        $this->assertGreaterThanOrEqual(14, $final->stageHistory()->count());
        $this->assertDatabaseHas('audit_logs', ['tenant_id' => $tenant->id, 'action' => 'application.stage_changed']);
        $this->actingAs($owner)->get(route('app.applications.show', $final->id))
            ->assertOk()->assertSee('Service Accountability')->assertSee($receptionist->name)->assertSee($typist->name);
    }

    private function processToGovernment($workflow, $application, $cashier, $typist, $supervisor, $pro): void
    {
        $this->move($workflow, $application, 'TYPING_QUEUE', $cashier);
        $this->move($workflow, $application, 'TYPING', $typist);
        $this->move($workflow, $application, 'QUALITY_CHECK', $typist);
        $approval = ApprovalRequest::withoutGlobalScopes()
            ->where('subject_type', 'application')->where('subject_id', $application->id)
            ->where('status', 'pending')->latest()->firstOrFail();
        $application->refresh()->load('currentStage');
        $this->assertTrue((bool) $application->currentStage->requires_approval);
        $this->assertSame('pending', $approval->status);

        try {
            $this->move($workflow, $application, 'READY_TO_SUBMIT', $supervisor);
            $this->fail('Approval gate did not block a pending quality check.');
        } catch (ValidationException $exception) {
            $this->assertStringContainsString('approval', strtolower(implode(' ', $exception->errors()['workflow'])));
        }

        $approval->update([
            'status' => 'approved', 'decision_notes' => 'Quality check passed.',
            'decided_by' => $supervisor->id, 'decided_at' => now(),
        ]);
        $this->move($workflow, $application, 'READY_TO_SUBMIT', $supervisor);
        $this->move($workflow, $application, 'GOVERNMENT_SUBMISSION', $pro);
    }

    private function move($workflow, $application, string $targetCode, User $user): void
    {
        $application->refresh()->load('currentStage', 'tenant', 'assignedUser');
        $target = WorkflowStage::where('service_id', $application->service_id)->where('stage_code', $targetCode)->firstOrFail();
        $workflow->executeTransition($application, $target, $user);
    }
}
