<?php

namespace App\Services;

use App\Models\Diagnosis;
use App\Models\Estimate;
use App\Models\JobCard;
use App\Models\VehicleInspection;
use App\Models\WorkOrder;
use Illuminate\Support\Facades\DB;

class WorkflowService
{
    public function __construct(
        private NotificationService $notificationService,
        private InspectionChecklistService $inspectionService
    ) {}

    /**
     * STEP 1: Vehicle Reception & Data Capture
     * Create job card when vehicle arrives with full data capture
     */
    public function createJobCard(array $data): JobCard
    {
        return DB::transaction(function () use ($data) {
            $jobCard = JobCard::create([
                'customer_id' => $data['customer_id'],
                'vehicle_id' => $data['vehicle_id'],
                'service_advisor_id' => $data['service_advisor_id'],
                'branch_code' => $data['branch_code'] ?? config('app.default_branch_code', 'ACC'),
                'arrival_datetime' => $data['arrival_datetime'] ?? now(),
                'mileage_in' => $data['mileage_in'] ?? null,
                'fuel_level_in' => $data['fuel_level_in'] ?? null,
                'customer_reported_issues' => $data['customer_reported_issues'] ?? '',
                'vehicle_condition_notes' => $data['vehicle_condition_notes'] ?? '',
                'keys_location' => $data['keys_location'] ?? 'service_desk',
                'personal_items_removed' => $data['personal_items_removed'] ?? false,
                'photos_taken' => $data['photos_taken'] ?? false,
                'expected_completion_date' => $data['expected_completion_date'] ?? null,
                'priority' => $data['priority'] ?? 'medium',
                'notes' => $data['notes'] ?? null,
                'status' => 'received', // Initial status
            ]);

            // STEP 2: Create incoming inspection checklist automatically
            if (isset($data['inspection_checklist'])) {
                $this->performInitialInspection($jobCard, $data, $data['inspector_id']);
            }

            return $jobCard;
        });
    }

    /**
     * STEP 2: Initial Inspection by Service Supervisor
     * Perform arrival inspection checklist
     */
    public function performInitialInspection(JobCard $jobCard, array $inspectionData, int $inspectorId): JobCard
    {
        // Update job card with inspection data
        $jobCard->update([
            'status' => JobCard::STATUS_INSPECTED,
            'mileage_in' => $inspectionData['mileage_in'],
            'fuel_level_in' => $inspectionData['fuel_level_in'],
            'incoming_inspection_data' => $inspectionData['inspection_checklist'],
        ]);

        // Send notification that inspection is complete and ready for diagnosis assignment
        $this->notificationService->sendInspectionCompletedNotification($jobCard);

        return $jobCard->fresh();
    }

    /**
     * STEP 3: Assignment to Service Coordination
     * Assign job card to service coordinator and start diagnosis
     */
    public function assignToServiceCoordinator(JobCard $jobCard, int $serviceCoordinatorId): Diagnosis
    {
        // Validate workflow progression - must complete initial inspection first
        if ($jobCard->status !== JobCard::STATUS_INSPECTED) {
            throw new \InvalidArgumentException('Initial vehicle inspection must be completed before assignment to service coordinator');
        }

        // Ensure incoming inspection exists
        if (! $jobCard->incomingInspection) {
            throw new \InvalidArgumentException('Incoming inspection record is required before proceeding to diagnosis');
        }

        $diagnosis = Diagnosis::create([
            'job_card_id' => $jobCard->id,
            'service_coordinator_id' => $serviceCoordinatorId,
            'customer_reported_issues' => $jobCard->customer_reported_issues,
            'diagnosis_status' => 'in_progress',
            'diagnosis_date' => now(),
        ]);

        $jobCard->update(['status' => 'assigned_for_diagnosis']);

        return $diagnosis;
    }

    /**
     * STEP 4: Start Diagnostic Process with Timesheet Tracking
     */
    public function startDiagnosisTimesheet(Diagnosis $diagnosis, int $technicianId): void
    {
        // Start timesheet for diagnosis
        $timesheet = Timesheet::create([
            'job_card_id' => $diagnosis->job_card_id,
            'technician_id' => $technicianId,
            'task_type' => 'diagnosis',
            'start_time' => now(),
            'description' => 'Diagnostic assessment',
            'status' => 'in_progress',
        ]);

        $diagnosis->update([
            'diagnosis_status' => 'in_progress',
            'assigned_technician_id' => $technicianId,
            'started_at' => now(),
        ]);
    }

    /**
     * STEP 5: Complete diagnosis and create estimate with customer notifications
     */
    public function completeDiagnosis(Diagnosis $diagnosis, array $diagnosisData, array $estimateItems): Estimate
    {
        return DB::transaction(function () use ($diagnosis, $diagnosisData, $estimateItems) {
            // Update diagnosis
            $diagnosis->update([
                'diagnostic_findings' => $diagnosisData['diagnostic_findings'],
                'root_cause_analysis' => $diagnosisData['root_cause_analysis'],
                'recommended_repairs' => $diagnosisData['recommended_repairs'],
                'additional_issues_found' => $diagnosisData['additional_issues_found'] ?? null,
                'priority_level' => $diagnosisData['priority_level'] ?? 'medium',
                'estimated_repair_time' => $diagnosisData['estimated_repair_time'],
                'parts_required' => $diagnosisData['parts_required'] ?? [],
                'labor_operations' => $diagnosisData['labor_operations'] ?? [],
                'special_tools_required' => $diagnosisData['special_tools_required'] ?? [],
                'safety_concerns' => $diagnosisData['safety_concerns'] ?? null,
                'customer_authorization_required' => $diagnosisData['customer_authorization_required'] ?? false,
                'diagnosis_status' => 'completed',
                'notes' => $diagnosisData['notes'] ?? null,
                'completed_at' => now(),
            ]);

            // Create estimate
            $estimate = Estimate::create([
                'job_card_id' => $diagnosis->job_card_id,
                'diagnosis_id' => $diagnosis->id,
                'estimate_number' => $this->generateEstimateNumber($diagnosis->jobCard->branch_code),
                'prepared_by_id' => $diagnosis->service_coordinator_id,
                'total_labor_cost' => $estimateItems['total_labor_cost'],
                'total_parts_cost' => $estimateItems['total_parts_cost'],
                'total_other_cost' => $estimateItems['total_other_cost'] ?? 0,
                'tax_amount' => $estimateItems['tax_amount'],
                'total_amount' => $estimateItems['total_amount'],
                'status' => 'sent',
                'notes' => $estimateItems['notes'] ?? null,
                'validity_period_days' => $estimateItems['validity_period_days'] ?? 30,
            ]);

            // Create estimate line items
            foreach ($estimateItems['line_items'] as $item) {
                $estimate->lineItems()->create($item);
            }

            // Update job card status
            $diagnosis->jobCard->update(['status' => 'estimate_sent']);

            // STEP 5: Send notifications to customer (email + SMS)
            $this->notificationService->sendEstimateNotification($estimate);

            return $estimate;
        });
    }

    /**
     * STEP 6: Handle estimate approval and notify team
     */
    public function approveEstimate(Estimate $estimate, string $approvalMethod = 'portal'): WorkOrder
    {
        return DB::transaction(function () use ($estimate, $approvalMethod) {
            // Update estimate
            $estimate->update([
                'customer_approval_status' => 'approved',
                'customer_approved_at' => now(),
                'customer_approval_method' => $approvalMethod,
                'status' => 'approved',
            ]);

            // Update job card
            $estimate->jobCard->update(['status' => 'approved']);

            // Notify team members about approval
            $this->notificationService->notifyEstimateApproved($estimate);

            // Create work order
            return $this->createWorkOrder($estimate);
        });
    }

    /**
     * STEP 7: Parts Procurement & Inventory Management
     */
    public function initiatePartsProcurement(Estimate $estimate): array
    {
        $procurementStatus = [];

        foreach ($estimate->lineItems()->where('type', 'part')->get() as $item) {
            // Check inventory availability
            $part = Part::find($item->part_id);

            if (! $part || $part->current_stock < $item->quantity) {
                // Create purchase order if parts are out of stock
                $procurementStatus[] = [
                    'part_id' => $item->part_id,
                    'part_name' => $item->description,
                    'required_quantity' => $item->quantity,
                    'available_stock' => $part->current_stock ?? 0,
                    'shortage' => $item->quantity - ($part->current_stock ?? 0),
                    'status' => 'procurement_required',
                    'action' => 'create_purchase_order',
                ];
            } else {
                // Reserve parts from inventory
                $part->decrement('current_stock', $item->quantity);
                $part->increment('reserved_stock', $item->quantity);

                $procurementStatus[] = [
                    'part_id' => $item->part_id,
                    'part_name' => $item->description,
                    'required_quantity' => $item->quantity,
                    'status' => 'reserved',
                    'action' => 'reserved_from_stock',
                ];
            }
        }

        return $procurementStatus;
    }

    /**
     * Assign work order to technician and start work
     */
    public function assignWorkOrder(WorkOrder $workOrder, int $technicianId): void
    {
        $workOrder->update([
            'assigned_technician_id' => $technicianId,
            'status' => 'assigned',
            'actual_start_time' => now(),
        ]);

        $workOrder->jobCard->update(['status' => 'in_progress']);
    }

    /**
     * Complete work order and perform quality check
     */
    public function completeWorkOrder(WorkOrder $workOrder, int $qualityCheckerId): void
    {
        $workOrder->update([
            'status' => 'quality_check',
            'actual_completion_time' => now(),
            'quality_checked_by_id' => $qualityCheckerId,
            'quality_check_date' => now(),
            'completion_percentage' => 100,
        ]);
    }

    /**
     * STEP 8: Final Inspection & Quality Assurance
     * Perform outgoing inspection and final quality check
     */
    public function performOutgoingInspection(JobCard $jobCard, array $inspectionData, int $inspectorId): void
    {
        // Create outgoing inspection
        $outgoingInspection = VehicleInspection::create([
            'job_card_id' => $jobCard->id,
            'vehicle_id' => $jobCard->vehicle_id,
            'inspector_id' => $inspectorId,
            'inspection_type' => 'outgoing',
            'current_mileage' => $inspectionData['mileage_out'],
            'fuel_level' => $inspectionData['fuel_level_out'],
            'inspection_checklist' => $inspectionData['inspection_checklist'],
            'photos' => $inspectionData['photos'] ?? [],
            'overall_condition' => $inspectionData['overall_condition'],
            'inspection_date' => now(),
            'notes' => $inspectionData['notes'] ?? null,
        ]);

        // Compare with incoming inspection using service
        $incomingInspection = $jobCard->incomingInspection;
        if ($incomingInspection) {
            $differences = $this->inspectionService->compareInspections($incomingInspection, $outgoingInspection);

            if (! empty($differences)) {
                // Generate quality alert for significant discrepancies
                $qualityAlert = $this->inspectionService->generateQualityAlert($jobCard, $differences);

                if (! empty($qualityAlert)) {
                    $this->notificationService->sendQualityAlert($jobCard, $differences);

                    $outgoingInspection->update([
                        'discrepancies_found' => $differences,
                        'follow_up_required' => true,
                    ]);

                    $jobCard->update(['status' => 'quality_review_required']);

                    return;
                }
            }
        }

        // No discrepancies, mark as completed
        $jobCard->update([
            'status' => 'completed',
            'mileage_out' => $inspectionData['mileage_out'],
            'fuel_level_out' => $inspectionData['fuel_level_out'],
            'completion_datetime' => now(),
        ]);

        // Notify customer that vehicle is ready
        $this->notificationService->notifyVehicleReady($jobCard);
    }

    /**
     * STEP 9: Accounting & Invoicing
     */
    public function generateFinalInvoice(JobCard $jobCard): array
    {
        $estimate = $jobCard->estimates()->where('status', 'approved')->first();
        $actualLabor = $jobCard->timesheets()->sum('billable_hours');
        $actualParts = $jobCard->workOrders()->with('usedParts')->get()
            ->flatMap->usedParts->sum('actual_cost');

        $invoiceData = [
            'job_card_id' => $jobCard->id,
            'estimate_amount' => $estimate->total_amount,
            'actual_labor_cost' => $actualLabor * $estimate->labor_rate,
            'actual_parts_cost' => $actualParts,
            'tax_amount' => ($actualLabor + $actualParts) * $estimate->tax_rate / 100,
            'total_amount' => ($actualLabor + $actualParts) * (1 + $estimate->tax_rate / 100),
            'variance_from_estimate' => null,
        ];

        $invoiceData['variance_from_estimate'] = $invoiceData['total_amount'] - $estimate->total_amount;

        return $invoiceData;
    }

    /**
     * STEP 10: Vehicle Delivery & Job Closure
     */
    public function closeJobCard(JobCard $jobCard, array $deliveryData): void
    {
        $jobCard->update([
            'status' => 'delivered',
            'delivery_method' => $deliveryData['delivery_method'],
            'customer_satisfaction_rating' => $deliveryData['satisfaction_rating'] ?? null,
            'completion_datetime' => now(),
            'delivered_by_id' => $deliveryData['delivered_by_id'] ?? auth()->id(),
            'delivery_notes' => $deliveryData['delivery_notes'] ?? null,
        ]);

        // Archive all associated documents
        $this->archiveJobCardDocuments($jobCard);
    }

    /**
     * STEP 11: Archive job card documents
     */
    private function archiveJobCardDocuments(JobCard $jobCard): void
    {
        // This would typically move documents to long-term storage
        // For now, we'll just mark them as archived
        $jobCard->update(['archived_at' => now()]);

        // Update related records
        $jobCard->inspections()->update(['archived' => true]);
        $jobCard->timesheets()->update(['archived' => true]);
        $jobCard->estimates()->update(['archived' => true]);
        $jobCard->workOrders()->update(['archived' => true]);
    }

    /**
     * Get workflow status for a job card
     */
    public function getWorkflowStatus(JobCard $jobCard): array
    {
        return [
            'job_card' => $jobCard,
            'incoming_inspection' => $jobCard->incomingInspection,
            'diagnosis' => $jobCard->diagnosis,
            'estimate' => $jobCard->estimates()->latest()->first(),
            'work_orders' => $jobCard->workOrders,
            'outgoing_inspection' => $jobCard->outgoingInspection,
            'completion_percentage' => $this->calculateCompletionPercentage($jobCard),
        ];
    }

    /**
     * Calculate completion percentage for a job card
     */
    private function calculateCompletionPercentage(JobCard $jobCard): int
    {
        $steps = [
            'received' => 10,
            'in_diagnosis' => 25,
            'estimate_sent' => 40,
            'approved' => 50,
            'in_progress' => 75,
            'quality_check' => 90,
            'completed' => 95,
            'delivered' => 100,
        ];

        return $steps[$jobCard->status] ?? 0;
    }
}
