<?php

namespace App\Services;

use App\Models\Machine;
use App\Models\WorkOrder;
use App\Models\Product;
use App\Models\MaintenanceLog;
use App\Models\ProductionPrediction;
use App\Models\MachineHealthScore;
use App\Models\MaterialForecast;
use App\Models\ProductionRiskAlert;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;

class IntelligenceEngineService
{
    /**
     * Run all intelligence calculations.
     */
    public function recalculateAll()
    {
        $this->predictWorkOrderDelays();
        $this->predictMachineFailures();
        $this->forecastMaterialShortages();
        $this->detectBottlenecks();
    }

    /**
     * Predict delays for active work orders.
     */
    public function predictWorkOrderDelays()
    {
        $activeOrders = WorkOrder::whereIn('status', ['released', 'in_progress'])->get();

        foreach ($activeOrders as $order) {
            // Simple logic: Calculate expected duration based on quantity and historical average
            // In a real scenario, we'd look at machine capacity. Base capacity is available in production_lines.
            
            $baseCapacity = $order->productionLine->capacity ?? 10; // units per hour
            if ($baseCapacity <= 0) $baseCapacity = 10;

            $hoursRequired = $order->quantity / $baseCapacity;
            $predictedCompletion = Carbon::parse($order->start_date ?? now())->addHours($hoursRequired);

            $delayProb = 0;
            if ($predictedCompletion->isAfter($order->end_date)) {
                $delayProb = 75; // high probability if math says it's late
            }

            ProductionPrediction::updateOrCreate(
                ['work_order_id' => $order->id],
                [
                    'predicted_completion_at' => $predictedCompletion,
                    'delay_probability' => $delayProb,
                    'risk_level' => $delayProb > 50 ? 'high' : ($delayProb > 20 ? 'medium' : 'low'),
                    'last_calculated_at' => now(),
                ]
            );

            if ($delayProb > 50) {
                $this->createAlert('delay', 'critical', "High Risk of Delay for {$order->work_order_no}", "Predicted completion is " . $predictedCompletion->format('Y-m-d H:i') . " which is after the deadline.", $order);
            }
        }
    }

    /**
     * Predict machine failures based on logs.
     */
    public function predictMachineFailures()
    {
        $machines = Machine::all();

        foreach ($machines as $machine) {
            $recentDowntime = MaintenanceLog::where('machine_id', $machine->id)
                ->where('created_at', '>', now()->subDays(30))
                ->sum('downtime_minutes');

            $healthScore = 100 - min(40, ($recentDowntime / 120) * 10); // Deduct for downtime
            
            // Further deduct if last maintenance was long ago
            $daysSinceMaintenance = $machine->last_maintenance_at ? $machine->last_maintenance_at->diffInDays(now()) : 60;
            $healthScore -= min(30, $daysSinceMaintenance / 2);
            
            $healthScore = max(10, $healthScore);
            $failureProb = 100 - $healthScore;

            MachineHealthScore::updateOrCreate(
                ['machine_id' => $machine->id],
                [
                    'health_score' => $healthScore,
                    'failure_probability' => $failureProb,
                    'estimated_failure_window_start' => now()->addDays($healthScore / 10),
                    'estimated_failure_window_end' => now()->addDays(($healthScore / 10) + 3),
                    'recommendation' => $healthScore < 60 ? 'Schedule preventative maintenance immediately.' : 'Regular monitoring required.',
                ]
            );

            if ($healthScore < 50) {
                $this->createAlert('failure', 'critical', "Machine Failure Risk: {$machine->name}", "Health score dropped to {$healthScore}%. Sudden failure predicted within days.", $machine);
            }
        }
    }

    /**
     * Forecast material shortages.
     */
    public function forecastMaterialShortages()
    {
        $rawMaterials = Product::where('category', 'raw_material')->get();

        foreach ($rawMaterials as $material) {
            $currentStock = $material->totalStock();
            
            // Calculate daily consumption from work orders
            // In this demo, we can use a randomized value based on active work orders or historical averages
            $dailyConsumption = DB::table('bom_items')
                ->join('boms', 'bom_items.bom_id', '=', 'boms.id')
                ->join('work_orders', 'work_orders.bom_id', '=', 'boms.id')
                ->where('bom_items.product_id', $material->id)
                ->whereIn('work_orders.status', ['released', 'in_progress'])
                ->sum('bom_items.quantity') / 7; // simplified weekly to daily

            if ($dailyConsumption <= 0) $dailyConsumption = 5; // fallback

            $daysRemaining = $currentStock / $dailyConsumption;
            $predictedShortage = now()->addDays($daysRemaining);

            MaterialForecast::updateOrCreate(
                ['product_id' => $material->id],
                [
                    'current_stock' => $currentStock,
                    'daily_consumption_avg' => $dailyConsumption,
                    'predicted_shortage_at' => $predictedShortage,
                    'recommended_purchase_quantity' => $dailyConsumption * 14, // 2 weeks supply
                ]
            );

            if ($daysRemaining < 5) {
                $this->createAlert('shortage', 'warning', "Material Shortage: {$material->name}", "Current stock will be depleted in approximately " . round($daysRemaining, 1) . " days.", $material);
            }
        }
    }

    /**
     * Detect bottlenecks in production lines.
     */
    public function detectBottlenecks()
    {
        // Identify stations with high WIP or long average delay
        // For now, we'll mark the machine with lowest health as a bottleneck
        $worstMachine = MachineHealthScore::orderBy('health_score', 'asc')->first();
        if ($worstMachine) {
            $machine = $worstMachine->machine;
            $line = $machine->productionLine;

            // Logic: if worst machine health < 60, it's a bottleneck
            if ($worstMachine->health_score < 60) {
                $this->createAlert('bottleneck', 'warning', "Bottleneck Detected: {$line->name}", "Machine {$machine->name} is underperforming, slowing down the entire line.", $line);
            }
        }
    }

    /**
     * Helper to create alerts.
     */
    private function createAlert($type, $severity, $title, $message, $alertable)
    {
        ProductionRiskAlert::updateOrCreate(
            [
                'type' => $type,
                'alertable_type' => get_class($alertable),
                'alertable_id' => $alertable->id,
                'is_read' => false,
            ],
            [
                'severity' => $severity,
                'title' => $title,
                'message' => $message,
            ]
        );
    }
}
