<?php

namespace App\Services;

use App\Models\Role;
use App\Models\Service;
use App\Models\Tenant;
use App\Models\WorkflowStage;
use App\Models\WorkflowTransition;
use Illuminate\Support\Facades\DB;

class UaeTypingCenterWorkflowService
{
    private const STAGES = [
        ['INTAKE', 'Customer Intake', 'استقبال الطلب', 'start', 'receptionist', 20, false, false, false, false, false, false, 'Confirm customer, applicant, service, branch and priority.'],
        ['DOCUMENT_CHECK', 'Document Collection & Verification', 'جمع وتدقيق المستندات', 'verification', 'receptionist', 30, true, false, false, false, false, false, 'Collect every mandatory applicant, sponsor and company document; verify validity and legibility.'],
        ['PAYMENT_PENDING', 'Payment & Receipt', 'الدفع وإصدار الإيصال', 'payment', 'cashier', 30, false, true, false, false, false, false, 'Collect the configured payment arrangement and issue the official receipt before typing starts.'],
        ['TYPING_QUEUE', 'Ready for Typing', 'جاهز للطباعة', 'internal_processing', 'typist', 30, false, false, false, false, false, false, 'Application is ready for assignment to an available typist.'],
        ['TYPING', 'Application Typing & Data Entry', 'طباعة وإدخال بيانات الطلب', 'internal_processing', 'typist', 60, false, false, false, false, false, false, 'Enter portal data exactly from verified records and complete internal validation.'],
        ['QUALITY_CHECK', 'Supervisor Quality Check', 'مراجعة المشرف', 'approval', 'processing_supervisor', 30, false, false, true, false, false, false, 'Supervisor compares the typed application against documents, fees and authority requirements.'],
        ['READY_TO_SUBMIT', 'Ready for Government Submission', 'جاهز للتقديم الحكومي', 'internal_processing', 'pro', 30, false, false, false, false, false, false, 'Prepare the correct authority portal, credentials and government fee arrangement.'],
        ['GOVERNMENT_SUBMISSION', 'Government Portal Submission', 'التقديم عبر البوابة الحكومية', 'government_submission', 'pro', 45, false, false, false, true, false, false, 'Submit to the configured UAE authority and record every government reference and receipt.'],
        ['GOVERNMENT_PROCESSING', 'Under Government Processing', 'قيد المعالجة الحكومية', 'government_submission', 'pro', 1440, false, false, false, true, false, false, 'Monitor the authority response without overwriting earlier submission attempts.'],
        ['GOVERNMENT_RETURNED', 'Returned for Correction', 'مرتجع للتصحيح', 'verification', 'typist', 60, false, false, false, true, false, false, 'Capture the authority reason, obtain corrections and begin a controlled resubmission.'],
        ['GOVERNMENT_APPROVED', 'Government Approved', 'تمت الموافقة الحكومية', 'approval', 'processing_supervisor', 30, false, false, false, true, false, false, 'Verify the authority approval and references before preparing customer outputs.'],
        ['OUTPUT_READY', 'Output Preparation', 'تجهيز المخرجات', 'internal_processing', 'typist', 45, false, false, false, false, true, false, 'Upload the final permit, visa, ID form, receipt or other government output.'],
        ['CUSTOMER_NOTIFICATION', 'Customer Notification & Collection', 'إشعار العميل والاستلام', 'internal_processing', 'customer_service', 60, false, false, false, false, true, true, 'Notify the customer through an approved channel and arrange secure collection or delivery.'],
        ['DELIVERED', 'Delivered & Closed', 'تم التسليم والإغلاق', 'completion', 'customer_service', 0, false, false, false, false, true, true, 'Record recipient acknowledgement and close the application.'],
        ['REJECTED', 'Government Rejected', 'مرفوض حكومياً', 'rejection', 'processing_supervisor', 0, false, false, false, true, false, false, 'Preserve the structured rejection reason and final authority response.'],
    ];

    private const TRANSITIONS = [
        ['INTAKE', 'DOCUMENT_CHECK', 'Start Document Check', 'applications.create', 'documents_pending', false, null, false],
        ['DOCUMENT_CHECK', 'PAYMENT_PENDING', 'Documents Verified — Send to Cashier', 'documents.upload', 'pending_payment', false, null, false],
        ['PAYMENT_PENDING', 'TYPING_QUEUE', 'Payment Confirmed — Queue for Typing', 'payments.collect', 'queued', false, null, false],
        ['TYPING_QUEUE', 'TYPING', 'Start Typing', 'applications.edit', 'processing', false, null, false],
        ['TYPING', 'QUALITY_CHECK', 'Submit for Supervisor Review', 'applications.edit', 'under_review', false, null, false],
        ['QUALITY_CHECK', 'READY_TO_SUBMIT', 'Approve Quality Check', 'applications.approve', 'ready_to_submit', true, null, false],
        ['READY_TO_SUBMIT', 'GOVERNMENT_SUBMISSION', 'Open Government Submission', 'applications.submit', 'ready_to_submit', false, null, false],
        ['GOVERNMENT_SUBMISSION', 'GOVERNMENT_PROCESSING', 'Record Government Submission', 'applications.submit', 'submitted', false, ['latest_submission_status' => ['submitted', 'approved']], false],
        ['GOVERNMENT_PROCESSING', 'GOVERNMENT_RETURNED', 'Record Government Return', 'applications.submit', 'returned', false, ['latest_submission_status' => ['returned']], true],
        ['GOVERNMENT_RETURNED', 'DOCUMENT_CHECK', 'Begin Correction & Resubmission', 'applications.edit', 'documents_pending', false, null, true],
        ['GOVERNMENT_PROCESSING', 'GOVERNMENT_APPROVED', 'Record Government Approval', 'applications.approve', 'approved', false, ['latest_submission_status' => ['approved']], false],
        ['GOVERNMENT_PROCESSING', 'REJECTED', 'Record Government Rejection', 'applications.reject', 'rejected', false, ['latest_submission_status' => ['rejected']], false],
        ['GOVERNMENT_APPROVED', 'OUTPUT_READY', 'Prepare Approved Output', 'applications.approve', 'output_pending', false, null, false],
        ['OUTPUT_READY', 'CUSTOMER_NOTIFICATION', 'Output Ready — Notify Customer', 'documents.upload', 'ready_for_delivery', false, null, false],
        ['CUSTOMER_NOTIFICATION', 'DELIVERED', 'Deliver & Close Application', 'communications.manage', 'delivered', false, ['requires_delivery_record' => true], false],
    ];

    public function ensureForService(Service $service, bool $refreshDefaults = false): array
    {
        return DB::transaction(function () use ($service, $refreshDefaults) {
            $stages = [];

            foreach (self::STAGES as $index => $definition) {
                [$code, $nameEn, $nameAr, $type, $roleSlug, $sla, $documents, $payment, $approval, $submission, $output, $notification, $instructions] = $definition;
                $role = $this->roleFor($service->tenant_id, $roleSlug);
                $existing = WorkflowStage::where('service_id', $service->id)->where('stage_code', $code)->first();
                $values = [
                    'tenant_id' => $service->tenant_id,
                    'service_id' => $service->id,
                    'stage_name_en' => $nameEn,
                    'stage_name_ar' => $nameAr,
                    'stage_type' => $type,
                    'display_order' => ($index + 1) * 10,
                    'assigned_role_id' => $role?->id,
                    'queue_role' => $roleSlug,
                    'sla_minutes' => $sla,
                    'is_customer_visible' => ! in_array($code, ['QUALITY_CHECK'], true),
                    'instructions' => $instructions,
                    'requires_documents' => $documents,
                    'requires_payment' => $payment,
                    'requires_approval' => $approval,
                    'requires_submission' => $submission,
                    'requires_output' => $output,
                    'requires_notification' => $notification,
                    'can_skip' => false,
                    'can_reopen' => in_array($code, ['DELIVERED', 'REJECTED'], true),
                ];

                if (! $existing) {
                    $existing = WorkflowStage::create(['stage_code' => $code] + $values);
                } elseif ($refreshDefaults) {
                    $existing->update($values);
                }
                $stages[$code] = $existing;
            }

            foreach (self::TRANSITIONS as $definition) {
                [$from, $to, $action, $permission, $status, $approval, $conditions, $returnPath] = $definition;
                $values = [
                    'tenant_id' => $service->tenant_id,
                    'service_id' => $service->id,
                    'action_name_en' => $action,
                    'required_permission' => $permission,
                    'condition_rules_json' => $conditions,
                    'payment_requirement' => $from === 'PAYMENT_PENDING' ? 'full_or_credit' : 'none',
                    'requires_approval' => $approval,
                    'notification_event' => $to === 'CUSTOMER_NOTIFICATION' ? 'application.output_ready' : null,
                    'creates_task' => ! in_array($to, ['DELIVERED', 'REJECTED'], true),
                    'target_application_status' => $status,
                    'is_return_path' => $returnPath,
                ];
                $transition = WorkflowTransition::where('service_id', $service->id)
                    ->where('from_stage_id', $stages[$from]->id)
                    ->where('to_stage_id', $stages[$to]->id)
                    ->first();
                if (! $transition) {
                    WorkflowTransition::create([
                        'from_stage_id' => $stages[$from]->id,
                        'to_stage_id' => $stages[$to]->id,
                    ] + $values);
                } elseif ($refreshDefaults) {
                    $transition->update($values);
                }
            }

            return ['stages' => count($stages), 'transitions' => count(self::TRANSITIONS)];
        });
    }

    public function installForTenant(Tenant $tenant, bool $refreshDefaults = false): array
    {
        $summary = ['services' => 0, 'stages' => 0, 'transitions' => 0];
        Service::withoutGlobalScopes()->where('tenant_id', $tenant->id)->each(function (Service $service) use (&$summary, $refreshDefaults) {
            $installed = $this->ensureForService($service, $refreshDefaults);
            $summary['services']++;
            $summary['stages'] += $installed['stages'];
            $summary['transitions'] += $installed['transitions'];
        });

        return $summary;
    }

    private function roleFor(int $tenantId, string $slug): ?Role
    {
        return Role::where('slug', $slug)->where('tenant_id', $tenantId)->first()
            ?? Role::where('slug', $slug)->whereNull('tenant_id')->first();
    }
}
