<?php

namespace App\Services;

use App\Models\Application;
use App\Models\ApplicationAssignment;
use App\Models\ApplicationDocument;
use App\Models\ApplicationFeeItem;
use App\Models\ApplicationParty;
use App\Models\ApplicationStageHistory;
use App\Models\AuditLog;
use App\Models\Branch;
use App\Models\Customer;
use App\Models\Service;
use App\Models\ServiceVersion;
use App\Models\Tenant;
use App\Models\User;
use App\Models\WorkflowStage;
use Illuminate\Support\Facades\DB;

class ApplicationService
{
    protected FeeEngineService $feeEngine;

    protected ApplicationNumberSequenceService $sequenceService;

    protected ServiceConfigurationResolver $configResolver;

    protected UaeTypingCenterWorkflowService $workflowTemplate;

    public function __construct(
        FeeEngineService $feeEngine,
        ApplicationNumberSequenceService $sequenceService,
        ServiceConfigurationResolver $configResolver,
        UaeTypingCenterWorkflowService $workflowTemplate
    ) {
        $this->feeEngine = $feeEngine;
        $this->sequenceService = $sequenceService;
        $this->configResolver = $configResolver;
        $this->workflowTemplate = $workflowTemplate;
    }

    public function createApplication(Tenant $tenant, Customer $customer, Service $service, array $data, ?User $user = null): Application
    {
        $branchId = $data['branch_id'] ?? auth()->user()?->default_branch_id;
        $branch = $branchId ? Branch::find($branchId) : null;
        $priority = $data['priority'] ?? 'normal';
        $applicantType = $data['applicant_type'] ?? 'individual';

        // Every service receives the production UAE intake-to-delivery lifecycle.
        $this->workflowTemplate->ensureForService($service);

        // 1. Resolve Published Service Version & Runtime Config Snapshot
        $publishedVersion = ServiceVersion::where('service_id', $service->id)->where('status', 'published')->latest()->first();
        $versionId = $publishedVersion?->id;
        $configSnapshot = $this->configResolver->resolve($service, $publishedVersion?->version_number);

        // 2. Calculate Fee Engine Breakdown & Priorities
        $calculatedFees = $this->feeEngine->calculateServiceFees($service, [
            'priority' => $priority,
            'company_id' => $data['company_id'] ?? null,
            'branch_id' => $branchId,
        ]);

        return DB::transaction(function () use ($tenant, $branch, $customer, $service, $versionId, $data, $priority, $applicantType, $calculatedFees, $configSnapshot, $user) {
            $appNumber = $this->sequenceService->generateNextNumber($tenant, $branch);
            $startStage = WorkflowStage::where('service_id', $service->id)->where('stage_type', 'start')->orderBy('display_order')->first()
                ?? WorkflowStage::where('service_id', $service->id)->orderBy('display_order')->first();

            $creatorId = $user ? $user->id : (auth()->id() ?? User::where('tenant_id', $tenant->id)->first()->id);

            // 3. Create Main Application Entity
            $app = Application::create([
                'tenant_id' => $tenant->id,
                'branch_id' => $branch?->id,
                'counter_id' => $data['counter_id'] ?? null,
                'application_number' => $appNumber,
                'customer_id' => $customer->id,
                'applicant_type' => $applicantType,
                'service_id' => $service->id,
                'service_version_id' => $versionId,
                'priority' => $priority,
                'status' => 'new',
                'current_stage_id' => $startStage?->id,
                'assigned_user_id' => $data['assigned_user_id'] ?? $creatorId,
                'assigned_department_id' => $startStage?->assigned_department_id,
                'payment_status' => 'unpaid',
                'document_status' => 'pending',
                'sla_status' => 'on_track',
                'gov_fee_total' => $calculatedFees['gov_fee'],
                'typing_fee_total' => $calculatedFees['typing_fee'],
                'service_charge_total' => $calculatedFees['service_charge'],
                'vat_total' => $calculatedFees['vat_amount'],
                'total_price' => $calculatedFees['total_price'],
                'sla_start_at' => now(),
                'workflow_started_at' => now(),
                'stage_entered_at' => now(),
                'warning_at' => now()->addMinutes((int) floor(($startStage?->sla_minutes ?? 120) * .75)),
                'due_at' => now()->addMinutes($startStage?->sla_minutes ?? 120),
                'created_by' => $creatorId,
                'attended_by' => $creatorId,
            ]);

            // 4. Record Multi-Party Relationships
            ApplicationParty::create([
                'application_id' => $app->id,
                'party_type' => 'primary_customer',
                'customer_id' => $customer->id,
            ]);

            if (! empty($data['company_id'])) {
                ApplicationParty::create([
                    'application_id' => $app->id,
                    'party_type' => 'company',
                    'company_id' => $data['company_id'],
                ]);
            }

            // 5. Immutable Fee Breakdown Snapshot
            if (! empty($calculatedFees['fee_components'])) {
                foreach ($calculatedFees['fee_components'] as $comp) {
                    ApplicationFeeItem::create([
                        'application_id' => $app->id,
                        'fee_code' => $comp['fee_code'],
                        'name_en' => $comp['name_en'],
                        'amount' => $comp['amount'],
                        'component_type' => $comp['component_type'],
                        'revenue_classification' => $comp['revenue_classification'],
                        'tax_behavior' => $comp['tax_behavior'],
                        'price_source' => $calculatedFees['applied_price_source'],
                    ]);
                }
            } else {
                ApplicationFeeItem::create([
                    'application_id' => $app->id,
                    'fee_code' => 'TOTAL',
                    'name_en' => $service->name_en,
                    'amount' => $calculatedFees['total_price'],
                    'component_type' => 'service_charge',
                    'revenue_classification' => 'company_revenue',
                    'price_source' => $calculatedFees['applied_price_source'],
                ]);
            }

            // 6. Record Document Requirements Checklist
            if (! empty($configSnapshot['document_rules'])) {
                foreach ($configSnapshot['document_rules'] as $rule) {
                    ApplicationDocument::create([
                        'application_id' => $app->id,
                        'document_rule_id' => $rule['id'],
                        'document_type_id' => $rule['document_type_id'] ?? null,
                        'display_name' => $rule['display_name'],
                        'is_mandatory' => $rule['is_mandatory'] ?? true,
                        'status' => 'pending',
                        'source_entity' => $rule['source_entity'] ?? 'applicant',
                    ]);
                }
            } else {
                $app->update(['document_status' => 'verified']);
            }

            // 7. Initial Stage Audit Trail
            if ($startStage) {
                ApplicationStageHistory::create([
                    'application_id' => $app->id,
                    'from_stage_id' => null,
                    'to_stage_id' => $startStage->id,
                    'action_name' => 'Application Initialized',
                    'performed_by' => $creatorId,
                    'remarks' => 'Universal Application Created via Front Desk Workspace',
                ]);

                ApplicationAssignment::create([
                    'application_id' => $app->id,
                    'assigned_from_id' => null,
                    'assigned_to_id' => $app->assigned_user_id,
                    'assignment_method' => 'intake_creator',
                    'reason' => 'Application opened at front desk intake.',
                    'assigned_by' => $creatorId,
                ]);
            }

            AuditLog::record('applications', 'application.created', $app, null, null, $user);

            return $app;
        });
    }
}
