<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Session;
use App\Services\BaplieParser;
use App\Services\ContainerIsoMapping;
use Carbon\Carbon;

class BaplieController extends Controller
{
       private function normalizeStatusToCode($status): string
    {
        if (empty($status)) return 'U';
        
        $status = strtoupper(trim($status));
        
        if (in_array($status, ['F', 'FULL', 'FCL', 'LADEN', 'LOADED', '5', 'L'])) {
            return '5';
        }
        
        if (in_array($status, ['E', 'EMPTY', 'MTY', 'MT', '4'])) {
            return '4';
        }
        
        return 'U';
    }
    
    private function statusCodeToText($statusCode): string
    {
        $code = $this->normalizeStatusToCode($statusCode);
        
        return match($code) {
            '5' => 'Full',
            '4' => 'Empty',
            default => 'Unknown'
        };
    }
   
  private function sanitizeContainerData($containers)
{
    return array_map(function($container) {
        $stringFields = [
            'container_no', 'iso_type', 'status', 'status_code', 'status_mapped',
            'size', 'type', 'type_group', 'jenis', 'full_empty',
            'bay', 'row', 'tier', 'location',
            'pol_locode', 'pod_locode', 'delivery_locode', 'inland_location_76',
            'bl_no', 'seal_no', 'booking_no', 'operator_code',
            'imdg_class', 'handling_instruction', 'peb_no', 'item_class',
            'arr_ts', 'arr_by', 'stop', 'keterangan', 'additional_info',
            'original_mea_type_code', 'original_nad_format'  // ✅ PRESERVE EDI fields
        ];

        foreach ($stringFields as $field) {
            if (isset($container[$field])) {
                if (is_array($container[$field])) {
                    $container[$field] = implode(', ', array_filter($container[$field]));
                } elseif (!is_null($container[$field])) {
                    // ✅ fix: trim biar gak ada spasi nyelip
                    $container[$field] = trim((string)$container[$field]);
                }
            }
        }

        $numericFields = ['weight_kg', 'set_temperature', 'humidity'];
        foreach ($numericFields as $field) {
            if (isset($container[$field]) && !is_numeric($container[$field])) {
                $container[$field] = 0;
            }
        }

        $booleanFields = ['is_reefer', 'enhanced_by_iso_mapping', 'updated_from_excel'];
        foreach ($booleanFields as $field) {
            if (isset($container[$field])) {
                $container[$field] = (bool) $container[$field];
            }
        }

        return $container;
    }, $containers);
}

    public function upload(Request $request)
    {
       

        try {
            $request->validate([
                'baplie_file' => 'nullable|file|max:5120',
                'excel_file' => 'nullable|file|max:5120'
            ], [
                'baplie_file.file' => 'The uploaded BAPLIE file is not valid.',
                'baplie_file.max' => 'BAPLIE file size must be less than 5MB.',
                'excel_file.file' => 'The uploaded Excel file is not valid.',
                'excel_file.max' => 'Excel file size must be less than 5MB.',
                'excel_file.mimes' => 'Excel file must be .xlsx or .xls format.'
            ]);

            $baplieFilePath = null;
            $excelFilePath = null;

            if (!$request->hasFile('baplie_file') && !$request->hasFile('excel_file')) {
                return redirect()->back()
                    ->withErrors(['file' => 'Please upload at least one file (BAPLIE or Excel).'])
                    ->withInput();
            }

            if ($request->hasFile('excel_file')) {
                $excelFile = $request->file('excel_file');
                $allowedExtensions = ['xlsx', 'xls'];
                $extension = strtolower($excelFile->getClientOriginalExtension());
                if (!in_array($extension, $allowedExtensions)) {
                    return redirect()->back()->withErrors(['excel_file' => 'Excel file must be .xlsx or .xls format.'])->withInput();
                }
                  session(['original_excel_filename' => $excelFile->getClientOriginalName()]);
            
                $excelFileName = time() . '_excel_' . $excelFile->getClientOriginalName();
                $excelFilePath = storage_path('app/excel_uploads/' . $excelFileName);
                File::makeDirectory(dirname($excelFilePath), 0755, true, true);
                $excelFile->move(storage_path('app/excel_uploads'), $excelFileName);
                Log::info('Excel file moved successfully', ['path' => $excelFilePath]);
            }

            if ($request->hasFile('baplie_file')) {
                $baplieFile = $request->file('baplie_file');
                $allowedExtensions = ['edi', 'txt'];
                $extension = strtolower($baplieFile->getClientOriginalExtension());
                if (!in_array($extension, $allowedExtensions)) {
                    return redirect()->back()->withErrors(['baplie_file' => 'BAPLIE file must be .edi or .txt format.'])->withInput();
                }
                   session(['original_baplie_filename' => $baplieFile->getClientOriginalName()]);
            
                $baplieFileName = time() . '_baplie_' . $baplieFile->getClientOriginalName();
                $baplieFilePath = storage_path('app/baplie_uploads/' . $baplieFileName);
                File::makeDirectory(dirname($baplieFilePath), 0755, true, true);
                $baplieFile->move(storage_path('app/baplie_uploads'), $baplieFileName);
                Log::info('BAPLIE file moved successfully', ['path' => $baplieFilePath]);
            }
            $voyageData = [];
            $containersData = [];
            $locationsData = [];

            if ($baplieFilePath && File::exists($baplieFilePath)) {
                $parser = new BaplieParser($baplieFilePath);
                $voyageData = $parser->getVoyageData();

                // ✅ DEBUG: Log voyage data after parsing
                Log::info('📦 Voyage Data After Parsing', [
                    'carrier_code' => $voyageData['carrier_code'] ?? 'NOT SET',
                    'voyage_no' => $voyageData['voyage_no'] ?? 'NOT SET',
                    'vessel_name' => $voyageData['vessel_name'] ?? 'NOT SET',
                    'call_sign' => $voyageData['call_sign'] ?? 'NOT SET',
                    'all_keys' => array_keys($voyageData)
                ]);

                if (!empty($voyageData['operator'])) {
                    session()->put('default_nad', $voyageData['operator']);
                }
                $voyageData['original_unb'] = $voyageData['interchange_datetime'] ?? null;
                $voyageData['original_dtm137'] = $voyageData['document_datetime'] ?? null;
                $voyageData['original_dtm178'] = $voyageData['departure_datetime'] ?? null;
                $voyageData['original_dtm136'] = $voyageData['arrival_datetime'] ?? null;
                $containersData = $parser->getContainersData();
                session()->put('voyage', $voyageData);
                session()->put('original_voyage', $voyageData);

                // ✅ DEBUG: Verify data saved to session
                Log::info('💾 Voyage Data Saved to Session', [
                    'carrier_code_in_session' => session('voyage.carrier_code', 'NOT IN SESSION')
                ]);
                if (empty($containersData)) {
                    Log::error('No containers parsed from BAPLIE');
                    return redirect()->back()->with('error', 'No data found in BAPLIE file');
                }
                $containerAnomalies = $this->calculateContainerAnomalies($containersData);
                $anomalySeverity = $this->classifyAnomalySeverity($containerAnomalies);
                $containerAnomalies['severity_classification'] = $anomalySeverity;

                session()->put('container_anomalies', $containerAnomalies);
                Log::info('Anomalies calculated from BAPLIE:', $containerAnomalies['summary']);
                $locationsData = method_exists($parser, 'getLocationsData') ? $parser->getLocationsData() : [];
                Log::info('BAPLIE data parsed successfully', ['containers_count' => count($containersData)]);
            }

            $excelProcessed = false;
            $updatedFromExcel = 0;
            $addedFromExcel = 0;
            if ($excelFilePath && File::exists($excelFilePath)) {
            Log::info('Processing Excel file', ['path' => $excelFilePath]);
            try {
                $excelData = $this->parseExcelFile($excelFilePath);
                $mergeResult = $this->mergeExcelWithBaplieData(
                    $containersData,    
                    $excelData,
                    $voyageData
                );

                // Hanya ambil data kontainer hasil merge
                $containersData = $mergeResult['containers'];
                    $voyageData = $mergeResult['voyage'];
                $updatedFromExcel = $mergeResult['updated_count'];
                $addedFromExcel = $mergeResult['added_count'];
                $excelProcessed = true;
                Log::info('Excel data merged successfully', ['total_after_merge' => count($containersData)]);
            } catch (\Exception $e) {
                    Log::error('Excel parsing error', ['message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine()]);
            }
        }

            
            $containersData = $this->sanitizeContainerData($containersData);
            session()->put('voyage', $voyageData);
            session()->put('containers', $containersData);  
            session()->put('locations', $locationsData);
            
            $mergedStats = $this->calculateMergedStatistics($containersData);
            
            $containerAnomalies = $this->calculateContainerAnomalies($containersData);
            
      
            
            session()->put('voyage', $voyageData);
            session()->put('containers', $containersData);
            session()->put('locations', $locationsData);
            session()->put('status_breakdown', $mergedStats['status_breakdown']);
            session()->put('jenis_breakdown', $mergedStats['jenis_breakdown']);
            session()->put('size_breakdown', $mergedStats['size_breakdown']);
            session()->put('reefer_statistics', $mergedStats['reefer_statistics'] ?? []);
            session()->put('iso_enhanced_count', $mergedStats['iso_enhanced_count']);
            session()->put('container_anomalies', $containerAnomalies);
            session()->put('last_container_count', count($containersData));
            session()->put('last_container_hash', md5(json_encode(array_column($containersData, 'container_no'))));
            session()->put('weight_debug', [
                'total_weight_tons' => $mergedStats['total_weight_tons'],
                'containers_with_weight' => $mergedStats['containers_with_weight'],
                'containers_with_position' => $mergedStats['containers_with_position'],
                'containers_without_position' => $mergedStats['containers_without_position'],
                'excel_processed' => $excelProcessed,
                'containers_updated_from_excel' => $updatedFromExcel,
                'containers_added_from_excel' => $addedFromExcel,
            ]);

            $countFull = $mergedStats['status_breakdown']['5']['count'] ?? 0;
            $countEmpty = $mergedStats['status_breakdown']['4']['count'] ?? 0;
            $countUnknown = $mergedStats['status_breakdown']['U']['count'] ?? 0;
            $containersWithWeight = $mergedStats['containers_with_weight'] ?? 0;
            $totalWeightTons = $mergedStats['total_weight_tons'] ?? 0;
            $totalContainers = count($containersData);
            $reeferCount = $mergedStats['reefer_statistics']['total_reefers'] ?? 0;
            $anomalyCount = $containerAnomalies['summary']['total_anomalies'] ?? 0;

            Log::info('Session data saved successfully');
            
            if ($baplieFilePath && File::exists($baplieFilePath)) {
                File::delete($baplieFilePath);
            }
            if ($excelFilePath && File::exists($excelFilePath)) {
                File::delete($excelFilePath);
            }

            $fileTypes = [];
            if ($request->hasFile('baplie_file')) $fileTypes[] = 'BAPLIE';
            if ($request->hasFile('excel_file')) $fileTypes[] = 'Excel';
            
            $message = sprintf(
                '%s file(s) uploaded successfully! Containers: %d (Full: %d, Empty: %d, Unknown: %d), With Weight: %d, Total Weight: %.2f tons',
                implode(' & ', $fileTypes),
                $totalContainers,
                $countFull,
                $countEmpty,
                $countUnknown,
                $containersWithWeight,
                $totalWeightTons
            );

            if ($mergedStats['iso_enhanced_count'] > 0) {
                $message .= sprintf(' (ISO Enhanced: %d)', $mergedStats['iso_enhanced_count']);
            }

            if ($excelProcessed) {
                if ($updatedFromExcel > 0 || $addedFromExcel > 0) {
                    $message .= sprintf(
                        ' (Excel: Verified %d existing BAPLIE containers, Added %d new containers)',
                        $updatedFromExcel,
                        $addedFromExcel
                    );
                }
            }
            
            if ($reeferCount > 0) {
                $message .= sprintf(' (Reefers: %d)', $reeferCount);
                if (($mergedStats['reefer_statistics']['with_temperature_set'] ?? 0) > 0) {
                    $message .= sprintf(' [%d with temp settings]', $mergedStats['reefer_statistics']['with_temperature_set']);
                }
            }
            
            if ($anomalyCount > 0) {
                $message .= sprintf('  Anomalies detected: %d', $anomalyCount);
            }
            
            return redirect()->route('dashboard')
                ->with('success', $message);
                    
        } catch (\Illuminate\Validation\ValidationException $e) {
            Log::error('Validation failed', ['errors' => $e->errors()]);
            
            if (isset($baplieFilePath) && $baplieFilePath && File::exists($baplieFilePath)) {
                File::delete($baplieFilePath);
            }
            if (isset($excelFilePath) && $excelFilePath && File::exists($excelFilePath)) {
                File::delete($excelFilePath);
            }
            
            return redirect()->back()
                ->withErrors($e->errors())
                ->withInput();
                
        } catch (\Exception $e) {
            Log::error('Upload/parsing error', [
                'message' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString()
            ]);
            
            if (isset($baplieFilePath) && $baplieFilePath && File::exists($baplieFilePath)) {
                File::delete($baplieFilePath);
            }
            if (isset($excelFilePath) && $excelFilePath && File::exists($excelFilePath)) {
                File::delete($excelFilePath);
            }
            
            return redirect()->back()->with('error', 'Error: ' . $e->getMessage());
        }
    }

 public function uploadAdditionalExcel(Request $request)
    {
        try {
            $request->validate([
                'excel_file' => 'required|file|mimes:xlsx,xls|max:5120'
            ], [
                'excel_file.required' => 'Please select an Excel file.',
                'excel_file.mimes' => 'Excel file must be .xlsx or .xls format.',
                'excel_file.max' => 'Excel file size must be less than 5MB.'
            ]);

            $existingContainers = session('containers', []);
            $voyageData = session('original_voyage', session('voyage', []));

            
            if (empty($existingContainers)) {
                return redirect()->back()->with('error', 'No BAPLIE data found. Please upload BAPLIE file first.');
            }

            $excelFile = $request->file('excel_file');
            $excelFileName = time() . '_additional_' . $excelFile->getClientOriginalName();
            $excelFilePath = storage_path('app/excel_uploads/' . $excelFileName);
            
            File::makeDirectory(dirname($excelFilePath), 0755, true, true);
            $excelFile->move(storage_path('app/excel_uploads'), $excelFileName);
            
            Log::info('Additional Excel file uploaded', ['path' => $excelFilePath]);

            $excelData = $this->parseExcelFile($excelFilePath);
            
            $mergeResult = $this->mergeExcelWithBaplieData($existingContainers, $excelData, $voyageData);
            $mergedContainers = $this->sanitizeContainerData($mergeResult['containers']);
            $containerAnomalies = $this->calculateContainerAnomalies($mergedContainers);
            $anomalySeverity = $this->classifyAnomalySeverity($containerAnomalies);
            $containerAnomalies['severity_classification'] = $anomalySeverity;
            session()->put('container_anomalies', $containerAnomalies);
            $mergedStats = $this->calculateMergedStatistics($mergedContainers);
            $containerAnomalies = $this->calculateContainerAnomalies($mergedContainers);
            
            Log::info('Additional Excel - Anomalies calculated:', [
                'total_anomalies' => $containerAnomalies['summary']['total_anomalies'] ?? 0,
                'empty_overweight' => $containerAnomalies['summary']['empty_overweight_count'] ?? 0,
                'duplicate_positions' => $containerAnomalies['summary']['duplicate_positions_count'] ?? 0,
            ]);
            
            session()->put('containers', $mergedContainers);
            session()->put('status_breakdown', $mergedStats['status_breakdown']);
            session()->put('jenis_breakdown', $mergedStats['jenis_breakdown']);
            session()->put('size_breakdown', $mergedStats['size_breakdown']);
            session()->put('reefer_statistics', $mergedStats['reefer_statistics'] ?? []);
            session()->put('iso_enhanced_count', $mergedStats['iso_enhanced_count']); 
            session()->put('container_anomalies', $containerAnomalies);
            session()->put('last_container_count', count($mergedContainers));
            session()->put('last_container_hash', md5(json_encode(array_column($mergedContainers, 'container_no'))));
            session()->put('weight_debug', [
                'total_weight_tons' => $mergedStats['total_weight_tons'],
                'containers_with_weight' => $mergedStats['containers_with_weight'],
                'containers_with_position' => $mergedStats['containers_with_position'],
                'containers_without_position' => $mergedStats['containers_without_position'],
                'last_excel_upload' => now()->format('Y-m-d H:i:s'),
            ]);
        
            if (File::exists($excelFilePath)) {
                File::delete($excelFilePath);
            }
            
            $message = sprintf(
                'Excel file processed successfully! Verified: %d existing BAPLIE containers, Added: %d new containers. Total containers: %d',
                $mergeResult['updated_count'],
                $mergeResult['added_count'],
                count($mergedContainers)
            );
            
            if ($mergedStats['iso_enhanced_count'] > 0) {
                $message .= sprintf(' (ISO Enhanced: %d)', $mergedStats['iso_enhanced_count']);
            }
            
            $reeferCount = $mergedStats['reefer_statistics']['total_reefers'] ?? 0;
            if ($reeferCount > 0) {
                $message .= sprintf(' (Reefers: %d)', $reeferCount);
                if (($mergedStats['reefer_statistics']['with_temperature_set'] ?? 0) > 0) {
                    $message .= sprintf(' [%d with temp settings]', $mergedStats['reefer_statistics']['with_temperature_set']);
                }
            }
            
            if ($containerAnomalies['summary']['total_anomalies'] > 0) {
                $message .= sprintf(' |  Total Anomalies: %d', $containerAnomalies['summary']['total_anomalies']);
            }
            
            return redirect()->route('baplie.management')
                ->with('success', $message)
                ->with('merge_log', $mergeResult['merge_log'] ?? []);
                
        } catch (\Exception $e) {
            Log::error('Additional Excel upload error', [
                'message' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            
            if (isset($excelFilePath) && File::exists($excelFilePath)) {
                File::delete($excelFilePath);
            }
            
            return redirect()->back()->with('error', 'Error uploading Excel: ' . $e->getMessage());
        }
    }

 public function uploadMultipleExcel(Request $request)
    {
        try {
            $request->validate([
                'excel_files' => 'required|array|min:1|max:5',
                'excel_files.*' => 'required|file|mimes:xlsx,xls|max:5120'
            ], [
                'excel_files.required' => 'Please select at least one Excel file.',
                'excel_files.max' => 'Maximum 5 Excel files allowed at once.',
                'excel_files.*.mimes' => 'All files must be .xlsx or .xls format.',
                'excel_files.*.max' => 'Each file size must be less than 5MB.'
            ]);

            $existingContainers = session('containers', []);
           $voyageData = session('original_voyage', session('voyage', []));

            
            if (empty($existingContainers)) {
                return redirect()->back()->with('error', 'No BAPLIE data found. Please upload BAPLIE file first.');
            }

            $totalUpdated = 0;
            $totalAdded = 0;
            $allMergeLogs = [];
            $mergedContainers = $existingContainers;
            
            foreach ($request->file('excel_files') as $index => $excelFile) {
                $excelFileName = time() . "_batch{$index}_" . $excelFile->getClientOriginalName();
                $excelFilePath = storage_path('app/excel_uploads/' . $excelFileName);
                
                File::makeDirectory(dirname($excelFilePath), 0755, true, true);
                $excelFile->move(storage_path('app/excel_uploads'), $excelFileName);
                
                Log::info("Processing batch Excel file #{$index}", ['file' => $excelFileName]);

                try {
                    $excelData = $this->parseExcelFile($excelFilePath);
                    $mergeResult = $this->mergeExcelWithBaplieData($mergedContainers, $excelData, $voyageData);
                    
                    $mergedContainers = $mergeResult['containers'];
                    $totalUpdated += $mergeResult['updated_count'];
                    $totalAdded += $mergeResult['added_count'];
                    
                    $allMergeLogs[] = "File #{$index}: {$excelFileName} - Updated: {$mergeResult['updated_count']}, Added: {$mergeResult['added_count']}";
                    
                } catch (\Exception $e) {
                    Log::error("Error processing batch file #{$index}", ['error' => $e->getMessage()]);
                    $allMergeLogs[] = "File #{$index}: ERROR - {$e->getMessage()}";
                }
                
                
                if (File::exists($excelFilePath)) {
                    File::delete($excelFilePath);
                }
            }
            
           
            $mergedContainers = $this->sanitizeContainerData($mergedContainers);
            $containerAnomalies = $this->calculateContainerAnomalies($mergedContainers);
            $anomalySeverity = $this->classifyAnomalySeverity($containerAnomalies);
            $containerAnomalies['severity_classification'] = $anomalySeverity;
            session()->put('container_anomalies', $containerAnomalies);
            $mergedStats = $this->calculateMergedStatistics($mergedContainers);
            $containerAnomalies = $this->calculateContainerAnomalies($mergedContainers);
            
            Log::info('Batch Excel - Anomalies calculated:', [
                'total_anomalies' => $containerAnomalies['summary']['total_anomalies'] ?? 0,
                'files_processed' => count($request->file('excel_files')),
            ]);
            
            session()->put('containers', $mergedContainers);
            session()->put('status_breakdown', $mergedStats['status_breakdown']);
            session()->put('jenis_breakdown', $mergedStats['jenis_breakdown']);
            session()->put('size_breakdown', $mergedStats['size_breakdown']);
            session()->put('reefer_statistics', $mergedStats['reefer_statistics'] ?? []);
            session()->put('iso_enhanced_count', $mergedStats['iso_enhanced_count']); 
            session()->put('container_anomalies', $containerAnomalies);
            session()->put('last_container_count', count($mergedContainers));
            session()->put('last_container_hash', md5(json_encode(array_column($mergedContainers, 'container_no'))));
            session()->put('weight_debug', [
                'total_weight_tons' => $mergedStats['total_weight_tons'],
                'containers_with_weight' => $mergedStats['containers_with_weight'],
                'containers_with_position' => $mergedStats['containers_with_position'],
                'containers_without_position' => $mergedStats['containers_without_position'],
                'last_batch_upload' => now()->format('Y-m-d H:i:s'),
                'files_in_batch' => count($request->file('excel_files')),
            ]);
            
            $message = sprintf(
                'Batch upload completed! Processed %d Excel files. Total Updated: %d, Added: %d. Final total: %d containers',
                count($request->file('excel_files')),
                $totalUpdated,
                $totalAdded,
                count($mergedContainers)
            );
            
            if ($mergedStats['iso_enhanced_count'] > 0) {
                $message .= sprintf(' (ISO Enhanced: %d)', $mergedStats['iso_enhanced_count']);
            }
            
            $reeferCount = $mergedStats['reefer_statistics']['total_reefers'] ?? 0;
            if ($reeferCount > 0) {
                $message .= sprintf(' (Reefers: %d)', $reeferCount);
                if (($mergedStats['reefer_statistics']['with_temperature_set'] ?? 0) > 0) {
                    $message .= sprintf(' [%d with temp]', $mergedStats['reefer_statistics']['with_temperature_set']);
                }
            }
            
            if ($containerAnomalies['summary']['total_anomalies'] > 0) {
                $message .= sprintf(' |  Anomalies: %d', $containerAnomalies['summary']['total_anomalies']);
            }
            
            return redirect()->route('baplie.management')
                ->with('success', $message)
                ->with('merge_logs', $allMergeLogs);
                
        } catch (\Exception $e) {
            Log::error('Batch Excel upload error', ['error' => $e->getMessage()]);
            return redirect()->back()->with('error', 'Batch upload error: ' . $e->getMessage());
        }
    }
   private function parseExcelFile($filePath)
    {
        // Delegate to BaplieParser
        $parser = new BaplieParser(null); 
        return $parser->parseExcelFile($filePath);
    }


    private function parseTemperatureFromExcel($tempStr)
    {
        if (empty($tempStr)) return null;
        
        // Handle various temperature formats: "-18", "-18°C", "-18.5 C", etc.
        $cleaned = preg_replace('/[^\d.-]/', '', trim($tempStr));
        
        if (is_numeric($cleaned)) {
            return floatval($cleaned);
        }
        
        return null;
    }

    private function parseTemperatureRange($rangeStr)
    {
        if (empty($rangeStr)) return null;
        
        // Handle formats like "-20 to -15", "-20:-15", "-20~-15"
        $separators = [' to ', ':', '~', '-', ' - '];
        
        foreach ($separators as $sep) {
           
            if (strpos($rangeStr, $sep) !== false && $sep !== '-') {
                $parts = explode($sep, $rangeStr);
                if (count($parts) >= 2) {
                    $min = $this->parseTemperatureFromExcel(trim($parts[0]));
                    $max = $this->parseTemperatureFromExcel(trim($parts[1]));
                    
                    if ($min !== null && $max !== null) {
                        return [
                            'min' => $min,
                            'max' => $max,
                            'unit' => 'CEL' 
                        ];
                    }
                }
                break;
            }
        }
        
        return null;
    }

    private function isReeferContainer($container)
    {
        // Check ISO type untuk reefer codes
        $isoType = strtoupper($container['iso_type'] ?? '');
        if (strlen($isoType) >= 3) {
            $typeChar = substr($isoType, 2, 1);
            
            if (in_array($typeChar, ['4', '5', '6'])) { 
                return true;
            }
        }
        
        // Check jika ada temperature setting
        if (!empty($container['set_temperature'])) {
            return true;
        }
        
        // Check type field
        $type = strtoupper($container['type'] ?? '');
        if (strpos($type, 'REEFER') !== false || strpos($type, 'RF') !== false) {
            return true;
        }
        
        return false;
    }

    // Helper untuk konversi suhu 
    private function convertToCelcius($value, $unit)
    {
        if (strtoupper($unit) === 'FAH') {
            return ($value - 32) * (5 / 9);
        }
        return $value;
    }

    // Method untuk grouping 
    private function groupTemperatureRange($tempCelcius)
    {
        if ($tempCelcius >= 15) return 'Chilled (+15°C)';
        if ($tempCelcius >= 2) return 'Fresh (2-14°C)';
        if ($tempCelcius >= -18) return 'Frozen (-18 to 1°C)';
        return 'Deep Frozen (<-18°C)';
    }

private function enrichWithIsoMapping($isoType)
{
    if (empty($isoType)) return null;
    
    $isoMap = ContainerIsoMapping::getIsoMap();
    $isoType = strtoupper(trim($isoType));
    
    //  Exact match
    if (isset($isoMap[$isoType])) {
        return $this->formatIsoMappingResult($isoMap[$isoType], $isoType);
    }
    
    //  Old code match
    foreach ($isoMap as $newCode => $data) {
        if (!empty($data['old_code']) && $data['old_code'] === $isoType) {
            Log::info("ISO old code found", ['input' => $isoType, 'mapped_to' => $newCode]);
            return $this->formatIsoMappingResult($data, $newCode);
        }
    }
    
    //  Pattern match (size + type)
    if (strlen($isoType) >= 3) {
        $sizeChar = substr($isoType, 0, 1);
        $typeChar = substr($isoType, 2, 1);
        
        foreach ($isoMap as $code => $data) {
            if (substr($code, 0, 1) === $sizeChar && substr($code, 2, 1) === $typeChar) {
                Log::info("ISO pattern matched", [
                    'input' => $isoType,
                    'pattern' => "$sizeChar..$typeChar",
                    'matched_code' => $code
                ]);
                return $this->formatIsoMappingResult($data, $code);
            }
        }
    }
    
    Log::debug("No ISO mapping found", ['iso_type' => $isoType]);
    return null;
}
private function formatIsoMappingResult($data, $isoCode)
{
    return [
        'iso_code_new' => $isoCode,
        'size' => $this->normalizeSizeFromIso($data['size'] ?? ''),
        'type_group' => $data['type_group'] ?? 'G',
        'jenis' => $this->normalizeJenisFromIso($data['jenis'] ?? 'dry'),
        'keterangan' => $data['keterangan'] ?? '',
        'old_code' => $data['old_code'] ?? null
    ];
}
private function normalizeSizeFromIso($size): string
{
    if (str_contains($size, '20')) return "20'";
    if (str_contains($size, '40')) return "40'";
    if (str_contains($size, '45')) return "45'";
    return 'Unknown';
}

private function normalizeJenisFromIso($jenis): string
{
    $jenis = strtolower($jenis);
    
    if (str_contains($jenis, 'general') || str_contains($jenis, 'dry')) return 'dry';
    if (str_contains($jenis, 'reefer')) return 'reefer';
    if (str_contains($jenis, 'flat')) return 'flat';
    if (str_contains($jenis, 'tank')) return 'tank';
    if (str_contains($jenis, 'open')) return 'open_top';
    
    return 'dry';
}
   private function normalizeStatus($status)
    {
        return $this->normalizeStatusToCode($status); 
    }

    private function mapStatusToText($status)
    {
        return $this->statusCodeToText($status); 
    }
private function mergeExcelWithBaplieData($baplieContainers, $excelData, $voyageData)
{
    if (!is_array($baplieContainers)) {
        $baplieContainers = [];
    }
    
    if (!is_array($excelData)) {
        return [
            'containers' => $baplieContainers,
            'voyage' => $voyageData,
            'updated_count' => 0,
            'added_count' => 0,
            'conflict_count' => 0,
            'merge_log' => ['Invalid Excel data format'],
            'anomalies' => $this->calculateContainerAnomalies($baplieContainers)
        ];
    }
    
    $excelContainers = $excelData['containers'] ?? [];
    
    // Handle case jika BAPLIE kosong tapi Excel ada
    if (empty($baplieContainers) && !empty($excelContainers)) {
        Log::info('mergeExcelWithBaplieData: BAPLIE kosong, gunakan Excel only', [
            'excel_count' => count($excelContainers)
        ]);
        
        $convertedContainers = [];
        foreach ($excelContainers as $excelContainer) {
            $converted = $this->convertExcelToBaplieFormat($excelContainer);
            if (!empty($converted['container_no'])) {
                $convertedContainers[] = $converted;
            }
        }
        
        return [
            'containers' => $convertedContainers,
            'voyage' => $voyageData,
            'updated_count' => 0,
            'added_count' => count($convertedContainers),
            'conflict_count' => 0,
            'merge_log' => ["No BAPLIE data found, using " . count($convertedContainers) . " Excel containers"],
            'anomalies' => $this->calculateContainerAnomalies($convertedContainers)
        ];
    }
    
    //  Handle case jika Excel kosong
    if (empty($excelContainers)) {
        Log::info('mergeExcelWithBaplieData: Excel kosong, gunakan BAPLIE only', [
            'baplie_count' => count($baplieContainers)
        ]);
        
        return [
            'containers' => $baplieContainers,
            'voyage' => $voyageData,
            'updated_count' => 0,
            'added_count' => 0,
            'conflict_count' => 0,
            'merge_log' => ['No Excel data, using BAPLIE only'],
            'anomalies' => $this->calculateContainerAnomalies($baplieContainers)
        ];
    }
    
    // PERBAIKAN 4: Main merge logic
    $mergedContainers = $baplieContainers;
    $updatedCount = 0;
    $addedCount = 0;
    $conflictCount = 0;
    $mergeLog = [];
    
    // Hitung anomalies SEBELUM merge
    $baplieAnomalies = $this->calculateContainerAnomalies($baplieContainers);
    Log::info('Anomalies in BAPLIE before merging:', [
        'total_anomalies' => $baplieAnomalies['summary']['total_anomalies'],
        'breakdown' => $baplieAnomalies['summary']
    ]);
    
    // ✅ PERBAIKAN 5: Loop Excel containers dengan validasi
    foreach ($excelContainers as $excelContainer) {
        $containerNumber = $excelContainer['container_no'] ?? '';

        // Skip jika container number kosong atau invalid
        if (empty($containerNumber) || strlen(trim($containerNumber)) < 4) {
            $mergeLog[] = "Skipped Excel container with invalid/empty number: '" . substr($containerNumber, 0, 20) . "'";
            continue;
        }

        $containerNumber = strtoupper(trim($containerNumber));

        // ✅ PERBAIKAN 6: Cari existing container dengan case-insensitive
        $existingIndex = null;
        foreach ($mergedContainers as $index => $baplieContainer) {
            $baplieNumber = strtoupper(trim($baplieContainer['container_no'] ?? ''));

            // Exact match
            if ($baplieNumber === $containerNumber) {
                $existingIndex = $index;
                break;
            }

            // Fuzzy match (untuk typo minor)
            if (!empty($baplieNumber) && levenshtein($baplieNumber, $containerNumber) <= 1) {
                Log::warning("Fuzzy match found during merge", [
                    'baplie' => $baplieNumber,
                    'excel' => $containerNumber
                ]);
                $existingIndex = $index;
                break;
            }
        }

        if ($existingIndex !== null) {
            // ✅ PERBAIKAN 7: Container sudah ada di BAPLIE
            // JANGAN UBAH spesifikasi BAPLIE, hanya LOG perbandingan
            list($mergedContainer, $conflicts) = $this->mergeContainerData(
                $mergedContainers[$existingIndex],
                $excelContainer
            );

            // ✅ FIX: Jangan update container, gunakan BAPLIE original
            // mergeContainerData() sekarang hanya mengembalikan conflicts, bukan perubahan
            // $mergedContainers[$existingIndex] tetap seperti aslinya dari BAPLIE

            if (!empty($conflicts)) {
                $conflictCount++;
                $mergeLog[] = "Container {$containerNumber}: VERIFIED against Excel - " . implode(' | ', $conflicts);
            } else {
                $mergeLog[] = "Container {$containerNumber}: VERIFIED in Excel (no changes made)";
            }

            // ✅ JANGAN increment updatedCount karena tidak ada yang di-update
            // Hanya verification saja
            // $updatedCount++; // ← COMMENT OUT INI!
        } else {
            // ✅ PERBAIKAN 8: Container baru dari Excel, convert format
            $newContainer = $this->convertExcelToBaplieFormat($excelContainer);

            // Validasi sebelum add
            if (!empty($newContainer['container_no'])) {
                $mergedContainers[] = $newContainer;
                $addedCount++;
                $mergeLog[] = "✅ New container {$containerNumber}: ADDED from Excel";
            } else {
                $mergeLog[] = "❌ Failed to add container {$containerNumber}: Conversion error";
            }
        }
    }
    
    // ✅ PERBAIKAN 9: Hitung anomalies SETELAH merge
    $mergedAnomalies = $this->calculateContainerAnomalies($mergedContainers);
    
    Log::info('Anomalies after merging:', [
        'total_anomalies' => $mergedAnomalies['summary']['total_anomalies'],
        'breakdown' => $mergedAnomalies['summary'],
        'comparison' => [
            'before' => $baplieAnomalies['summary']['total_anomalies'],
            'after' => $mergedAnomalies['summary']['total_anomalies'],
            'change' => $mergedAnomalies['summary']['total_anomalies'] - $baplieAnomalies['summary']['total_anomalies']
        ]
    ]);
    
    // ✅ PERBAIKAN 10: Return result dengan informasi lengkap
    return [
        'containers' => $mergedContainers,
        'voyage' => $voyageData,
        'updated_count' => $updatedCount,
        'added_count' => $addedCount,
        'conflict_count' => $conflictCount,
        'merge_log' => $mergeLog,
        'anomalies' => $mergedAnomalies,
        'merge_summary' => [
            'baplie_original_count' => count($baplieContainers),
            'excel_count' => count($excelContainers),
            'merged_total_count' => count($mergedContainers),
            'anomalies_before' => $baplieAnomalies['summary']['total_anomalies'],
            'anomalies_after' => $mergedAnomalies['summary']['total_anomalies'],
            'anomalies_change' => $mergedAnomalies['summary']['total_anomalies'] - $baplieAnomalies['summary']['total_anomalies']
        ]
    ];
}

private function mergeContainerData($baplieContainer, $excelContainer)
{
    $conflicts = [];
    $merged = $baplieContainer;

    // ✅ FIX: Jangan ubah spesifikasi container BAPLIE
    // Container BAPLIE hanya di-log jika ada perbedaan dengan Excel
    // Field-field yang DIPERBOLEHKAN untuk di-update dari Excel hanya:
    // - booking_no (jika kosong di BAPLIE)
    // - seal_no (jika kosong di BAPLIE)
    // - bay, row, tier (HANYA jika kosong di BAPLIE)

    // Field yang TIDAK BOLEH DIUBAH dari BAPLIE:
    // - weight_kg (JANGAN ubah, simpan BAPLIE weight)
    // - status (JANGAN ubah, simpan BAPLIE status)
    // - iso_type (JANGAN ubah, simpan BAPLIE ISO type)
    // - pod_locode (JANGAN ubah, simpan BAPLIE POD)
    // - reefer fields (JANGAN ubah, simpan BAPLIE reefer info)

    // Hanya update field-field yang optional/empty di BAPLIE
    $updateIfEmptyMapping = [
        'booking_no' => ['baplie_field' => 'bl_no'],
        'seal_no' => ['baplie_field' => 'seal_no'],
        'bay' => ['baplie_field' => 'bay'],
        'row' => ['baplie_field' => 'row'],
        'tier' => ['baplie_field' => 'tier'],
    ];

    foreach ($updateIfEmptyMapping as $excelField => $config) {
        $excelValue = $excelContainer[$excelField] ?? null;
        $baplieField = $config['baplie_field'];
        $baplieValue = $merged[$baplieField] ?? null;

        // Skip jika value Excel kosong
        if ($excelValue === null || $excelValue === '') continue;

        // ✅ HANYA update jika BAPLIE kosong
        if (empty($baplieValue) || $baplieValue === '0' || $baplieValue === 0) {
            $merged[$baplieField] = $excelValue;
            $conflicts[] = "$excelField: filled from Excel (was empty in BAPLIE)";
        } elseif ($baplieValue != $excelValue) {
            // Jika BAPLIE sudah ada tapi berbeda → JANGAN ubah, hanya log
            $conflicts[] = "$excelField: BAPLIE kept '$baplieValue' (Excel has '$excelValue')";
        }
    }

    // ✅ CHECK untuk perbedaan di field-field KRITIS (jangan ubah, tapi log warning)
    $criticalFields = [
        'weight_kg' => 'weight_kg',
        'status' => 'status',
        'status_code' => 'status_code',
        'iso_type' => 'iso_type',
        'pod_locode' => 'pod_locode',
        'is_reefer' => 'is_reefer',
        'set_temperature' => 'set_temperature',
        'temperature_range' => 'temperature_range',
        'original_mea_type_code' => 'original_mea_type_code',      // ✅ PROTECT MEA type
        'original_nad_format' => 'original_nad_format',            // ✅ PROTECT NAD format
    ];

    foreach ($criticalFields as $excelField => $baplieField) {
        $excelValue = $excelContainer[$excelField] ?? null;
        $baplieValue = $merged[$baplieField] ?? null;

        // Skip jika value Excel kosong
        if ($excelValue === null || $excelValue === '') continue;

        // ✅ JANGAN ubah, tapi LOG CONFLICT jika berbeda
        if (!empty($baplieValue) && $baplieValue != $excelValue) {
            // PERBAIKAN: Gunakan BAPLIE value, jangan Excel value
            // Ini memastikan data BAPLIE tetap original
            $conflicts[] = "⚠️  $excelField: BAPLIE '$baplieValue' KEPT (Excel had '$excelValue') - NO CHANGE";
        }
    }

    // ✅ JANGAN update metadata untuk "updated from Excel"
    // Karena container BAPLIE tidak diubah
    // Hanya yang ditambah saja yang punya metadata "updated_from_excel"

    return [$merged, $conflicts];
}
private function convertExcelToBaplieFormat($excelContainer)
{
    // PERBAIKAN: Normalize status lebih hati-hati
    $rawStatus = $excelContainer['status'] ?? '';
    $statusCode = $this->normalizeStatusToCode($rawStatus);
    
    // PERBAIKAN: Parse weight dengan handling untuk ton vs kg
    $rawWeight = $excelContainer['weight_kg'] ?? 0;
    $weightKg = 0;
    if (is_numeric($rawWeight)) {
        $weightKg = floatval($rawWeight);
        // Auto-convert tons to kg (jika < 100, assume tons)
        if ($weightKg > 0 && $weightKg < 100) {
            $weightKg *= 1000;
        }
    }
    $polLocode = 'IDSRG';
    
    return [
        'container_no' => strtoupper(trim($excelContainer['container_no'] ?? '')),
        'iso_type' => strtoupper(trim($excelContainer['iso_type'] ?? '')),
        'status' => $statusCode,
        'status_code' => $statusCode,
        'status_mapped' => $this->statusCodeToText($statusCode),
        'weight_kg' => $weightKg,
        'weight_details' => $this->createWeightDetails($weightKg),
        'primary_weight_type' => $weightKg > 0 ? 'Gross Weight (Excel)' : null,
        'bay' => trim($excelContainer['bay'] ?? ''),
        'row' => trim($excelContainer['row'] ?? ''),
        'tier' => trim($excelContainer['tier'] ?? ''),
        'pol_locode' => $polLocode,
        'pod_locode' => strtoupper(trim($excelContainer['pod_locode'] ?? '')),
        'delivery_locode' => strtoupper(trim($excelContainer['delivery_locode'] ?? '')),
        'bl_no' => $excelContainer['booking_no'] ?? $excelContainer['bl_no'] ?? '',
        'seal_no' => $excelContainer['seal_no'] ?? '',
        'imdg_class' => $excelContainer['imdg_class'] ?? '',
        'handling_instruction' => $excelContainer['handling_instruction'] ?? '',
        'operator_code' => $excelContainer['operator_code'] ?? '',
        'size' => $this->extractSizeFromExcel($excelContainer),
        'type_group' => $this->deriveTypeGroup($excelContainer['iso_type'] ?? ''),
        'jenis' => $this->deriveJenisFromExcel($excelContainer),
        'keterangan' => 'Excel Import',
        'locations' => $excelContainer['locations'] ?? [],
        'source' => 'excel',
        'additional_data' => $excelContainer['additional_data'] ?? [],
        'updated_from_excel' => true,
        'excel_import_timestamp' => now()->toDateTimeString(),
        'is_reefer' => $excelContainer['is_reefer'] ?? false,
        'set_temperature' => $excelContainer['set_temperature'] ?? null,
        'temperature_unit' => $excelContainer['temperature_unit'] ?? 'CEL',
        'temperature_settings' => $excelContainer['temperature_settings'] ?? [],
        'temperature_range' => $excelContainer['temperature_range'] ?? null,
        'reefer_instructions' => $excelContainer['reefer_instructions'] ?? null,
        'enhanced_by_iso_mapping' => false,
        'additional_info' => $excelContainer['additional_info'] ?? '',  // ✅ FTX field
        'inland_location_76' => $excelContainer['inland_location_76'] ?? '',  // ✅ LOC+76 field
        'original_mea_type_code' => 'WT',  // Default untuk Excel imports
        'original_nad_format' => null  // Will be set from default_nad if needed
    ];
}
// Fungsi baru: Implementasi deriveTypeGroup (contoh sederhana berdasarkan ISO type)
private function deriveTypeGroup($isoType)
{
    $isoType = strtoupper(trim($isoType ?? ''));
    if (empty($isoType)) return 'unknown';
    
    // Contoh mapping: Berdasarkan prefix dan suffix ISO (e.g., 22G1 → standard dry)
    if (strpos($isoType, 'R') !== false || strpos($isoType, 'REEFER') !== false) {
        return 'reefer';
    } elseif (strpos($isoType, 'T') !== false || strpos($isoType, 'TANK') !== false) {
        return 'tank';
    } elseif (strpos($isoType, 'O') !== false || strpos($isoType, 'OPEN') !== false) {
        return 'open_top';
    } elseif (strpos($isoType, 'F') !== false || strpos($isoType, 'FLAT') !== false) {
        return 'flat_rack';
    }
    
    return 'G'; // Default untuk dry cargo
}

private function mapExcelStatusToBaplie($status)
{
    $status = strtoupper(trim($status));
    
    if (in_array($status, ['FULL', 'F', 'FCL', 'LADEN'])) {
        return '5'; // Full dalam format BAPLIE
    } elseif (in_array($status, ['EMPTY', 'E', 'MTY', 'MT'])) {
        return '4'; // Empty dalam format BAPLIE
    }
    
    return 'U'; // Unknown
}

private function createWeightDetails($weight)
{
    if (empty($weight) || floatval($weight) <= 0) {
        return [];
    }
    
    return [[
        'type_code' => 'WT',
        'type_description' => 'Gross Weight',
        'value_kg' => floatval($weight)
    ]];
}

private function extractSizeFromExcel($container)
{
    // Coba dari size field langsung
    if (!empty($container['size'])) {
        $size = trim($container['size']);
        if (preg_match('/(\d{2})/', $size, $matches)) { 
            return $matches[1] . "'";
        }
    }
    
    // Coba dari ISO type
    if (!empty($container['iso_type'])) {
        $iso = strtoupper($container['iso_type']);
        if (strlen($iso) >= 1) {
            $sizeChar = substr($iso, 0, 1);
            if ($sizeChar === '2') return "20'";
            if ($sizeChar === '4') return "40'";
            if ($sizeChar === 'L') return "45'"; 
        }
    }
    
    return 'Unknown';
}

private function deriveJenisFromExcel($excelContainer) 
{
    $type = strtoupper($excelContainer['type'] ?? '');
    
    if (strpos($type, 'DRY') !== false) return 'dry';
    if (strpos($type, 'REEFER') !== false) return 'reefer';
    if (strpos($type, 'FLAT') !== false) return 'flat';
    if (strpos($type, 'TANK') !== false) return 'tank';
    if (strpos($type, 'OPEN') !== false) return 'open_top';
    
    
    $status = strtoupper($excelContainer['status'] ?? '');
    if (in_array($status, ['EMPTY', 'E', 'MTY'])) {
        return 'empty';
    }
    
    return 'dry'; // default
}
/**
 * Calculate statistics for merged data
 */

private function calculateMergedStatistics($containers)
{
    $statusBreakdown = [
        '5' => ['count' => 0, 'weight_kg' => 0],
        '4' => ['count' => 0, 'weight_kg' => 0],
        'U' => ['count' => 0, 'weight_kg' => 0]
    ];
    $jenisBreakdown = [];
    $sizeBreakdown = [];
    $typeGroupBreakdown = [];
    $isoEnhancedCount = 0;
    
    // ✅ KONSISTEN: Hanya hitung weight > 0
    $totalWeight = 0;
    $containersWithWeight = 0;
    $containersWithPosition = 0;
    
    $reeferStats = [
        'total_reefers' => 0,
        'with_temperature_set' => 0,
        'with_temperature_range' => 0,
        'temperature_distribution' => [],
        'average_temperature' => null
    ];
    $temperaturesCelcius = [];

    foreach ($containers as $container) {
        // ✅ Status breakdown - use unified method
        $statusCode = $this->normalizeStatusToCode($container['status_code'] ?? $container['status'] ?? 'U');
        
        if (!isset($statusBreakdown[$statusCode])) {
            $statusBreakdown[$statusCode] = ['count' => 0, 'weight_kg' => 0];
        }
        $statusBreakdown[$statusCode]['count']++;
        
        // ✅ Weight - KONSISTEN
        $weight = floatval($container['weight_kg'] ?? 0);
        if ($weight > 0) {
            $totalWeight += $weight;
            $containersWithWeight++;
            $statusBreakdown[$statusCode]['weight_kg'] += $weight;
        }
        
        // Size breakdown
        $size = $container['size'] ?? 'Unknown';
        if (!isset($sizeBreakdown[$size])) {
            $sizeBreakdown[$size] = ['count' => 0, 'weight_kg' => 0];
        }
        $sizeBreakdown[$size]['count']++;
        $sizeBreakdown[$size]['weight_kg'] += $weight;
        
        // Jenis breakdown
        $jenis = $container['jenis'] ?? 'Unknown';
        if (!isset($jenisBreakdown[$jenis])) {
            $jenisBreakdown[$jenis] = ['count' => 0, 'weight_kg' => 0];
        }
        $jenisBreakdown[$jenis]['count']++;
        $jenisBreakdown[$jenis]['weight_kg'] += $weight;
        
        // Type Group breakdown
        $typeGroup = $container['type_group'] ?? 'Unknown';
        if (!isset($typeGroupBreakdown[$typeGroup])) {
            $typeGroupBreakdown[$typeGroup] = ['count' => 0, 'weight_kg' => 0];
        }
        $typeGroupBreakdown[$typeGroup]['count']++;
        $typeGroupBreakdown[$typeGroup]['weight_kg'] += $weight;
        
        // Position count
        if (!empty($container['bay']) && !empty($container['row']) && !empty($container['tier'])) {
            $containersWithPosition++;
        }
        
        // ISO enhanced count
        if ($container['enhanced_by_iso_mapping'] ?? false) {
            $isoEnhancedCount++;
        }
        
        // Reefer statistics
        if ($container['is_reefer'] ?? false) {
            $reeferStats['total_reefers']++;

            if (!empty($container['set_temperature'])) {
                $reeferStats['with_temperature_set']++;
                
                $temp = $container['set_temperature'];
                $unit = $container['temperature_unit'] ?? 'CEL';
                $tempCelcius = $this->convertToCelcius($temp, $unit);
                $temperaturesCelcius[] = $tempCelcius;

                $tempGroup = $this->groupTemperatureRange($tempCelcius);
                if (!isset($reeferStats['temperature_distribution'][$tempGroup])) {
                    $reeferStats['temperature_distribution'][$tempGroup] = 0;
                }
                $reeferStats['temperature_distribution'][$tempGroup]++;
            }

            if (!empty($container['temperature_range'])) {
                $reeferStats['with_temperature_range']++;
            }
        }
    }
    
    // Calculate average temperature
    if (!empty($temperaturesCelcius)) {
        $reeferStats['average_temperature'] = round(array_sum($temperaturesCelcius) / count($temperaturesCelcius), 1);
    }
    
    return [
        'status_breakdown' => $statusBreakdown,
        'jenis_breakdown' => $jenisBreakdown,
        'size_breakdown' => $sizeBreakdown,
        'type_group_breakdown' => $typeGroupBreakdown,
        'total_weight' => $totalWeight,
        'total_weight_tons' => round($totalWeight / 1000, 2),
        'average_weight_kg' => $containersWithWeight > 0 ? round($totalWeight / $containersWithWeight, 2) : 0,
        'iso_enhanced_count' => $isoEnhancedCount,
        'total_containers' => count($containers),
        'containers_with_weight' => $containersWithWeight,
        'containers_with_position' => $containersWithPosition,
        'containers_without_position' => count($containers) - $containersWithPosition,
        'reefer_statistics' => $reeferStats
    ];
}
    private function getFilePreview($filePath, $lines = 10)
    {
        try {
            $content = File::get($filePath);
            $linesArray = explode("\n", $content);
            return array_slice($linesArray, 0, $lines);
        } catch (\Exception $e) {
            return ['Error reading file: ' . $e->getMessage()];
        }
    }

    /**
     * Debug weight parsing - Route untuk troubleshooting
     */
    public function debugWeight()
    {
        $debugInfo = session('weight_debug', []);
        $containers = session('containers', []);
         $totalWeight = session('total_weight', 0); // tambahin ini

    \Log::info('DebugWeight called', [
        'debugInfo' => $debugInfo,
        'containers_count' => count($containers),
        'total_weight' => $totalWeight,
    ]);
        
        return response()->json([
            'debug_info' => $debugInfo,
            'sample_containers' => array_slice($containers, 0, 5),
            'total_containers' => count($containers)
        ]);
    }

    /**
     * Update container di session
     */
    public function updateContainer(Request $request, $index)
    {
        $containers = session()->get('containers', []);

        if (!isset($containers[$index])) {
            return redirect()->route('baplie.management')->with('error', 'Container tidak ditemukan di session.');
        }

        // Validasi data 
        $validatedData = $request->validate([
            'container_no' => 'required|string|max:15', 
            'iso_type' => 'nullable|string|max:4',
            'status' => 'nullable|string|max:10',
            'bay' => 'nullable|string|max:3|regex:/^[0-9]+$/', 
            'row' => 'nullable|string|max:2|regex:/^[0-9]+$/', 
            'tier' => 'nullable|string|max:2|regex:/^[0-9]+$/', 
            'weight_kg' => 'nullable|numeric|min:0',
            'pol_locode' => 'nullable|string|max:5',
            'pod_locode' => 'nullable|string|max:5',
            'delivery_locode' => 'nullable|string|max:5',
            'bl_no' => 'nullable|string|max:35',
            'operator_code' => 'nullable|string|max:10',
            'imdg_class' => 'nullable|string|max:10',
            'handling_instruction' => 'nullable|string|max:100',
            'size' => 'nullable|string|max:50',
            'size_custom' => 'nullable|string|max:50',
            'type_group' => 'nullable|string|max:50',
            'type_group_custom' => 'nullable|string|max:50',
            'jenis' => 'nullable|string|max:50',
            'jenis_custom' => 'nullable|string|max:50',
            'full_empty' => 'nullable|string|max:10',
            'is_reefer' => 'nullable|boolean',
            'set_temperature' => 'nullable|numeric|between:-50,50',
            'temperature_unit' => 'nullable|in:CEL,FAH',
            'temp_range_min' => 'nullable|numeric|between:-50,50',
            'temp_range_max' => 'nullable|numeric|between:-50,50',
            'reefer_instructions' => 'nullable|string|max:200',
            'ventilation' => 'nullable|string|max:50',
            'humidity' => 'nullable|numeric|between:0,100',
        ]);

        if (($validatedData['size'] ?? '') === 'other' && !empty($validatedData['size_custom'])) {
            $validatedData['size'] = $validatedData['size_custom'];
        }
        
        if (($validatedData['type_group'] ?? '') === 'other' && !empty($validatedData['type_group_custom'])) {
            $validatedData['type_group'] = $validatedData['type_group_custom'];
        }
        
        if (($validatedData['jenis'] ?? '') === 'other' && !empty($validatedData['jenis_custom'])) {
            $validatedData['jenis'] = $validatedData['jenis_custom'];
        }

        unset($validatedData['size_custom']);
        unset($validatedData['type_group_custom']);
        unset($validatedData['jenis_custom']);

        if (isset($validatedData['bay'])) {
            $bay = preg_replace('/\D/', '', $validatedData['bay']); // Hapus non-digit
            $validatedData['bay'] = $bay ? str_pad($bay, 3, '0', STR_PAD_LEFT) : '';
        }
        
        if (isset($validatedData['row'])) {
            $row = preg_replace('/\D/', '', $validatedData['row']);
            $validatedData['row'] = $row ? str_pad($row, 2, '0', STR_PAD_LEFT) : '';
        }
        
        if (isset($validatedData['tier'])) {
            $tier = preg_replace('/\D/', '', $validatedData['tier']);
            $validatedData['tier'] = $tier ? str_pad($tier, 2, '0', STR_PAD_LEFT) : '';
        }

        if (!empty($validatedData['status'])) {
            if ($validatedData['status'] === 'F' || $validatedData['status'] === '5') {
                $validatedData['full_empty'] = 'FULL';
                $validatedData['status'] = '5'; // Normalize to code
                $validatedData['status_code'] = '5';
            } elseif ($validatedData['status'] === 'E' || $validatedData['status'] === '4') {
                $validatedData['full_empty'] = 'EMPTY';
                $validatedData['status'] = '4'; // Normalize to code
                $validatedData['status_code'] = '4';
            }
        }

        $fieldsToUpdate = [
            'container_no', 'iso_type', 'status', 'status_code', 'bay', 'row', 'tier', 
            'weight_kg', 'pol_locode', 'pod_locode', 'delivery_locode', 
            'bl_no', 'operator_code', 'imdg_class', 'handling_instruction',
            'size', 'type_group', 'jenis', 'full_empty',
            'is_reefer', 'set_temperature', 'temperature_unit', 'reefer_instructions',
            'ventilation', 'humidity'
        ];

        foreach ($fieldsToUpdate as $field) {
            if (array_key_exists($field, $validatedData)) {
                $containers[$index][$field] = $validatedData[$field];
            }
        }

        if (isset($validatedData['temp_range_min']) && isset($validatedData['temp_range_max'])) {
            $containers[$index]['temperature_range'] = [
                'min' => $validatedData['temp_range_min'],
                'max' => $validatedData['temp_range_max'],
                'unit' => $validatedData['temperature_unit'] ?? 'CEL'
            ];
        }

        if (($validatedData['is_reefer'] ?? false)) {
            $containers[$index]['jenis'] = 'reefer';
        }

        if (!empty($validatedData['status'])) {
            $containers[$index]['status_mapped'] = $this->mapContainerStatus($validatedData['status']);
        }

        Log::info('🔧 Container updated:', [
            'index' => $index,
            'container_no' => $containers[$index]['container_no'],
            'bay_saved' => $containers[$index]['bay'],
            'row_saved' => $containers[$index]['row'],
            'tier_saved' => $containers[$index]['tier'],
            'status_saved' => $containers[$index]['status'],
        ]);

        session()->put('containers', $containers);
        
        session()->save();
        session()->forget('container_anomalies'); 
        session()->forget('last_container_hash');
        session()->forget('last_container_count');
        
        $this->recalculateBreakdowns();

        return redirect()->route('baplie.management')
            ->with('success', 'Container berhasil diperbarui!')
            ->with('force_reload_anomalies', true)
            ->with('trigger_reload', true);
    }

private function recalculateBreakdowns()
{
    $containers = session('containers', []);
    
    //  Status breakdown dengan kode standar
    $statusBreakdown = [
        '5' => ['count' => 0, 'weight_kg' => 0],
        '4' => ['count' => 0, 'weight_kg' => 0],
        'U' => ['count' => 0, 'weight_kg' => 0],
    ];
    
    $sizeBreakdown = [];
    $jenisBreakdown = [];

    // ✅ PERBAIKAN: Tambahkan total weight calculation
    $totalWeight = 0;

    foreach ($containers as $container) {
        // ✅ Use unified status normalization
        $statusCode = $this->normalizeStatusToCode($container['status_code'] ?? $container['status'] ?? 'U');

        $weight = floatval($container['weight_kg'] ?? 0);

        // ✅ PERBAIKAN: Akumulasi total weight
        if ($weight > 0) {
            $totalWeight += $weight;
        }

        $statusBreakdown[$statusCode]['count']++;
        if ($weight > 0) {
            $statusBreakdown[$statusCode]['weight_kg'] += $weight;
        }
        
        // Size breakdown
        $size = $this->getContainerSize($container);
        if (!isset($sizeBreakdown[$size])) {
            $sizeBreakdown[$size] = ['count' => 0, 'weight_kg' => 0];
        }
        $sizeBreakdown[$size]['count']++;
        if ($weight > 0) {
            $sizeBreakdown[$size]['weight_kg'] += $weight;
        }
        
        // Jenis breakdown
        $jenis = $this->determineJenisFromContainer($container);
        if (!isset($jenisBreakdown[$jenis])) {
            $jenisBreakdown[$jenis] = ['count' => 0, 'weight_kg' => 0];
        }
        $jenisBreakdown[$jenis]['count']++;
        if ($weight > 0) {
            $jenisBreakdown[$jenis]['weight_kg'] += $weight;
        }
    }
    
    // Update session
    session()->put('status_breakdown', $statusBreakdown);
    session()->put('size_breakdown', $sizeBreakdown);
    session()->put('jenis_breakdown', $jenisBreakdown);

    // ✅ PERBAIKAN: Simpan total weight ke session
    session()->put('total_weight', $totalWeight);

    // ✅ CRITICAL: Recalculate anomalies
    $containerAnomalies = $this->calculateContainerAnomalies($containers);
    session()->put('container_anomalies', $containerAnomalies);
    session()->put('last_container_count', count($containers));
    session()->put('last_container_hash', md5(json_encode(array_column($containers, 'container_no'))));

    Log::info('✅ Breakdowns and anomalies recalculated:', [
        'total_containers' => count($containers),
        'total_weight_kg' => $totalWeight,
        'total_weight_tons' => round($totalWeight / 1000, 1),
        'status_breakdown' => $statusBreakdown,
        'total_anomalies' => $containerAnomalies['summary']['total_anomalies'] ?? 0
    ]);
}private function calculateContainerAnomalies($containers)
{
    // Standard empty container weights (in kg)
    $emptyWeightStandards = [
"20'-Dry"    => ['min' => 2150, 'max' => 2300], // Kontainer Paling Umum
    "20'-HC"     => ['min' => 2200, 'max' => 2450], // Jarak jarang, sering disamakan dengan Dry
    "20'-Reefer" => ['min' => 2800, 'max' => 3200], // Berat karena mesin
    "20'-OT"     => ['min' => 2300, 'max' => 2500],
    "20'-FR"     => ['min' => 2500, 'max' => 2900],
    "20'-TK"     => ['min' => 3500, 'max' => 4200],

    // 40 Kaki
    "40'-Dry"    => ['min' => 3600, 'max' => 3850], 
    "40'-HC"     => ['min' => 3800, 'max' => 4100], // Paling umum untuk 40'
    "40'-Reefer" => ['min' => 4500, 'max' => 5000], // Reefer 40' hampir selalu HC
    "40'-OT"     => ['min' => 3800, 'max' => 4200],
    "40'-FR"     => ['min' => 4800, 'max' => 5500],
    "40'-TK"     => ['min' => 6000, 'max' => 7000], // Sangat berat / Khusus

    // 45 Kaki (Biasanya HC)
    "45'-Dry"    => ['min' => 4500, 'max' => 4800], // Jarak jarang
    "45'-HC"     => ['min' => 4650, 'max' => 4950], // Standar Pallet Wide
    "45'-Reefer" => ['min' => 5200, 'max' => 6000],
];

    $maxLoadedWeights = [
        "20'-Dry" => 35000,
        "20'-HC" => 35000,
        "20'-Reefer" => 35000,
        "20'-OT" => 35000,
        "20'-FR" => 35000,
        "20'-TK" => 35000,
        
        "40'-Dry" => 35000,
        "40'-HC" => 35000,
        "40'-Reefer" => 35000,
        "40'-OT" => 35000,
        "40'-FR" => 35000,
        "40'-TK" => 35000,
        
        "45'-Dry" => 35000,
        "45'-HC" => 35000,
        "45'-Reefer" => 35000,
    ];
    
    $anomalies = [
        'empty_overweight' => [],
        'empty_underweight' => [],
        'status_weight_mismatch' => [],
        'unknown_status_heavy' => [],
        'full_overload' => [],
        'duplicate_container_ids' => [],
        'duplicate_positions' => [],
        'missing_container_id' => [],      
        'missing_position' => [],        
        'invalid_position' => [],
        'missing_weight' => [],  
        'invalid_bay_parity' => [],
        'summary' => [
            'total_anomalies' => 0,
            'empty_overweight_count' => 0,
            'empty_underweight_count' => 0,
            'status_mismatch_count' => 0,
            'unknown_heavy_count' => 0,
            'full_overload_count' => 0,
            'duplicate_ids_count' => 0,
            'duplicate_positions_count' => 0,
            'missing_id_count' => 0,           
            'missing_position_count' => 0,     
            'invalid_position_count' => 0,
            'missing_weight_count' => 0, 
            'invalid_bay_parity_count' => 0, 
        ]
    ];
    
    $containerIdTracker = [];
    $positionTracker = [];
    
    foreach ($containers as $index => $container) {
        // NORMALISASI KONSISTEN
        $containerNo = strtoupper(trim($container['container_no'] ?? ''));
        
        // CHECK 1: Missing Container ID
        if (empty($containerNo) || strlen($containerNo) < 4 || $containerNo === 'UNKNOWN') {
            $anomalies['missing_container_id'][] = [
                'index' => $index,
                'container_no' => $containerNo ?: 'EMPTY',
                'row_number' => $index + 1,
                'severity' => 'critical',
                'probable_issue' => ' Nomor kontainer kosong atau tidak valid.',
                'impact' => 'Cannot track or identify container in system'
            ];
            $anomalies['summary']['missing_id_count']++;
            
            if ($anomalies['summary']['missing_id_count'] <= 3) {
                Log::warning('🚨 Missing Container ID detected:', [
                    'index' => $index,
                    'container_no_raw' => $container['container_no'] ?? 'null',
                    'sample_data' => array_slice($container, 0, 5)
                ]);
            }
        }
        
        // CHECK 2: Missing Position
        $bay = trim($container['bay'] ?? $container['Bay'] ?? $container['BAY'] ?? '');
        $row = trim($container['row'] ?? $container['Row'] ?? $container['ROW'] ?? '');
        $tier = trim($container['tier'] ?? $container['Tier'] ?? $container['TIER'] ?? '');     
        $hasMissingPosition = (
            $bay === '' || 
            $row === '' || 
            $tier === '' ||
            $bay === null ||
            $row === null ||
            $tier === null
        );
        
        $hasZeroPosition = (
            ($bay === '0' || $bay === '00' || $bay === '000') &&
            ($row === '0' || $row === '00') &&
            ($tier === '0' || $tier === '00')
        );
        
        if ($hasMissingPosition || $hasZeroPosition) {
            $anomalies['missing_position'][] = [
                'index' => $index,
                'container_no' => $containerNo,
                'bay' => $bay ?: 'EMPTY',
                'row' => $row ?: 'EMPTY',
                'tier' => $tier ?: 'EMPTY',
                'position_string' => ($bay ?: '???') . '-' . ($row ?: '??') . '-' . ($tier ?: '??'),
                'severity' => 'high',
                'probable_issue' => ' Data posisi kontainer kosong',
                'impact' => 'Cannot determine physical location on vessel '
            ];
            $anomalies['summary']['missing_position_count']++;
            
            if ($anomalies['summary']['missing_position_count'] <= 3) {
                Log::warning(' Missing Position detected:', [
                    'container_no' => $containerNo,
                    'bay' => $bay,
                    'row' => $row,
                    'tier' => $tier
                ]);
            }
        } else {
            // Validate format: Bay (3 digit), Row (2 digit), Tier (2 digit)
            $isValidBay = preg_match('/^\d{1,3}$/', $bay);
            $isValidRow = preg_match('/^\d{1,2}$/', $row);
            $isValidTier = preg_match('/^\d{1,2}$/', $tier);
            
            if (!$isValidBay || !$isValidRow || !$isValidTier) {
                $anomalies['invalid_position'][] = [
                    'index' => $index,
                    'container_no' => $containerNo,
                    'bay' => $bay,
                    'row' => $row,
                    'tier' => $tier,
                    'position_string' => "$bay-$row-$tier",
                    'issues' => [
                        'bay' => !$isValidBay ? 'Invalid format (expected 1-3 digits)' : 'OK',
                        'row' => !$isValidRow ? 'Invalid format (expected 1-2 digits)' : 'OK',
                        'tier' => !$isValidTier ? 'Invalid format (expected 1-2 digits)' : 'OK',
                    ],
                    'severity' => 'medium',
                    'probable_issue' => 'Format posisi kontainer tidak valid.',
                    'impact' => 'May cause errors in stowage planning systems'
                ];
                $anomalies['summary']['invalid_position_count']++;
            }
        }
        // ✅ NEW CHECK: Bay parity validation based on container size
            if ($isValidBay) {
                $bayNum = intval($bay);
                $size = $this->getContainerSize($container);

                $isOdd = $bayNum % 2 !== 0;
                $isEven = $bayNum % 2 === 0;

                $isSize20 = str_contains($size, "20");
                $isSize40 = str_contains($size, "40");
                $isSize45 = str_contains($size, "45");

                $isParityMismatch = 
                    ($isSize20 && !$isOdd) ||      // 20ft harus ganjil
                    (($isSize40 || $isSize45) && !$isEven); // 40ft & 45ft harus genap

                if ($isParityMismatch) {
                    $anomalies['invalid_bay_parity'][] = [
                        'index' => $index,
                        'container_no' => $containerNo,
                        'bay' => $bay,
                        'size' => $size,
                        'severity' => 'medium',
                        'probable_issue' => "Bay $bay tidak sesuai dengan aturan ukuran ($size)",
                        'impact' => 'Posisi kontainer mungkin salah slot (stowage inconsistency)'
                    ];
                    $anomalies['summary']['invalid_bay_parity_count'] = 
                        ($anomalies['summary']['invalid_bay_parity_count'] ?? 0) + 1;
                }
            }

        // ✅ FIX: CHECK 3 - MISSING WEIGHT (PINDAHKAN KE SINI, SEBELUM WEIGHT VALIDATIONS)
        $size = $this->getContainerSize($container);
        $weight = floatval($container['weight_kg'] ?? 0);
        $status = $container['status_mapped'] ?? 'Unknown';
        
        if ($weight <= 0) {
            $containerType = $this->getContainerType($container);
            
            $anomalies['missing_weight'][] = [
                'index' => $index,
                'container_no' => $containerNo,
                'size' => $size,
                'type' => $containerType,
                'weight_kg' => $weight,
                'status' => $status,
                'severity' => 'medium',
                'probable_issue' => 'Data berat kontainer kosong',
                'impact' => 'Stowage planning & crane load calculation may be inaccurate'
            ];
            $anomalies['summary']['missing_weight_count']++;
            
            // Log hanya 3 pertama untuk debugging
            if ($anomalies['summary']['missing_weight_count'] <= 3) {
                Log::warning('⚠️ Missing Weight detected:', [
                    'container_no' => $containerNo,
                    'weight_kg' => $weight,
                    'status' => $status
                ]);
            }
            
            continue; // ✅ Skip weight validation checks jika weight = 0
        }
        
        // ===== WEIGHT-BASED CHECKS (hanya jika weight > 0) =====
        $containerType = $this->getContainerType($container);
        $lookupKey = $size . '-' . $containerType;
        
        if (!isset($emptyWeightStandards[$lookupKey])) {
            Log::debug("No weight standard for: $lookupKey", [
                'container_no' => $containerNo,
                'size' => $size,
                'type' => $containerType
            ]);
            continue;
        }
        
        $emptyStd = $emptyWeightStandards[$lookupKey];
        $maxLoaded = $maxLoadedWeights[$lookupKey] ?? 35000;
        
        // Weight anomaly checks (existing)
        if ($status === 'Empty') {
            if ($weight > $maxLoaded) {
                $anomalies['empty_overweight'][] = [
                    'index' => $index,
                    'container_no' => $containerNo,
                    'size' => $size,
                    'type' => $containerType,
                    'weight_kg' => $weight,
                    'weight_ton' => round($weight / 1000, 2),
                    'status' => $status,
                    'max_loaded_weight' => $maxLoaded,
                    'excess_weight' => $weight - $maxLoaded,
                    'severity' => $this->calculateAnomalySeverity($weight, $maxLoaded, 'overweight'),
                    'probable_issue' => 'Berat kontainer melebihi batas untuk status Empty'
                ];
                $anomalies['summary']['empty_overweight_count']++;
            } elseif ($weight < $emptyStd['min']) {
                $anomalies['empty_underweight'][] = [
                    'index' => $index,
                    'container_no' => $containerNo,
                    'size' => $size,
                    'type' => $containerType,
                    'weight_kg' => $weight,
                    'weight_ton' => round($weight / 1000, 2),
                    'status' => $status,
                    'min_empty_weight' => $emptyStd['min'],
                    'weight_deficit' => $emptyStd['min'] - $weight,
                    'severity' => $this->calculateAnomalySeverity($weight, $emptyStd['min'], 'underweight'),
                    'probable_issue' => 'Berat kontainer terlalu rendah untuk status Empty'
                ];
                $anomalies['summary']['empty_underweight_count']++;
            }
        } elseif ($status === 'Full') {
            if ($weight >= $emptyStd['min'] && $weight <= $emptyStd['max']) {
                $anomalies['status_weight_mismatch'][] = [
                    'index' => $index,
                    'container_no' => $containerNo,
                    'size' => $size,
                    'type' => $containerType,
                    'weight_kg' => $weight,
                    'weight_ton' => round($weight / 1000, 2),
                    'reported_status' => $status,
                    'probable_actual_status' => 'Empty',
                    'empty_weight_range' => $emptyStd,
                    'severity' => 'medium',
                    'probable_issue' => 'Berat terlalu rendah untuk status “Full”'
                ];
                $anomalies['summary']['status_mismatch_count']++;
            }
            
            if ($weight > $maxLoaded) {
                $anomalies['full_overload'][] = [
                    'index' => $index,
                    'container_no' => $containerNo,
                    'size' => $size,
                    'type' => $containerType,
                    'weight_kg' => $weight,
                    'weight_ton' => round($weight / 1000, 2),
                    'status' => $status,
                    'max_gross_weight' => $maxLoaded,
                    'excess_weight' => $weight - $maxLoaded,
                    'excess_weight_ton' => round(($weight - $maxLoaded) / 1000, 2),
                    'severity' => $this->calculateAnomalySeverity($weight, $maxLoaded, 'overweight'),
                    'probable_issue' => 'Berat kontainer melebihi batas maksimum (Overload). ',
                    'safety_risk' => 'HIGH - Structural integrity risk, may damage ship/port equipment'
                ];
                $anomalies['summary']['full_overload_count']++;
            }
        } elseif ($status === 'Unknown' && $weight > ($emptyStd['max'] * 1.5)) {
            $anomalies['unknown_status_heavy'][] = [
                'index' => $index,
                'container_no' => $containerNo,
                'size' => $size,
                'type' => $containerType,
                'weight_kg' => $weight,
                'weight_ton' => round($weight / 1000, 2),
                'status' => $status,
                'probable_actual_status' => 'Full',
                'empty_weight_range' => $emptyStd,
                'severity' => 'low',
                'probable_issue' => 'Status unknown tapi memiliki berat.'
            ];
            $anomalies['summary']['unknown_heavy_count']++;
        }
        
        // Duplicate Container IDs check
        if (isset($containerIdTracker[$containerNo])) {
            $anomalies['duplicate_container_ids'][] = [
                'container_no' => $containerNo,
                'first_occurrence_index' => $containerIdTracker[$containerNo],
                'duplicate_index' => $index,
                'severity' => 'high',
                'probable_issue' => 'ID kontainer duplikat'
            ];
            $anomalies['summary']['duplicate_ids_count']++;
        } else {
            $containerIdTracker[$containerNo] = $index;
        }
        
        // Duplicate Positions check (only for valid positions)
        if (!$hasMissingPosition && !$hasZeroPosition) {
            $positionKey = $bay . '-' . $row . '-' . $tier;
            
            if (isset($positionTracker[$positionKey])) {
                $anomalies['duplicate_positions'][] = [
                    'position' => $positionKey,
                    'bay' => $bay,
                    'row' => $row,
                    'tier' => $tier,
                    'first_container' => $positionTracker[$positionKey]['container_no'],
                    'first_index' => $positionTracker[$positionKey]['index'],
                    'duplicate_container' => $containerNo,
                    'duplicate_index' => $index,
                    'severity' => 'critical',
                    'probable_issue' => 'Duplikat posisi kontainer'
                ];
                $anomalies['summary']['duplicate_positions_count']++;
            } else {
                $positionTracker[$positionKey] = [
                    'container_no' => $containerNo,
                    'index' => $index
                ];
            }
        }
    }
    
    //  UPDATE TOTAL ANOMALIES (tambahkan missing_weight_count)
    $anomalies['summary']['total_anomalies'] = 
        $anomalies['summary']['empty_overweight_count'] +
        $anomalies['summary']['empty_underweight_count'] +
        $anomalies['summary']['status_mismatch_count'] +
        $anomalies['summary']['unknown_heavy_count'] +
        $anomalies['summary']['full_overload_count'] +
        $anomalies['summary']['duplicate_ids_count'] +
        $anomalies['summary']['duplicate_positions_count'] +
        $anomalies['summary']['missing_id_count'] +          
        $anomalies['summary']['missing_position_count'] +   
        $anomalies['summary']['invalid_position_count'] +
        $anomalies['summary']['missing_weight_count']+
         $anomalies['summary']['invalid_bay_parity_count']; 
    
    Log::info(' Anomaly calculation completed:', [
        'total_containers' => count($containers),
        'total_anomalies' => $anomalies['summary']['total_anomalies'],
        'breakdown' => $anomalies['summary'],
        'critical_issues' => [
            'missing_ids' => $anomalies['summary']['missing_id_count'],
            'missing_positions' => $anomalies['summary']['missing_position_count'],
            'duplicate_positions' => $anomalies['summary']['duplicate_positions_count'],
            'full_overload' => $anomalies['summary']['full_overload_count'],
            'missing_weight' => $anomalies['summary']['missing_weight_count'],  // ✅ TAMBAHKAN INI
        ],
        'sample_anomaly_containers' => array_slice(
            array_merge(
                array_column($anomalies['full_overload'] ?? [], 'container_no'),
                array_column($anomalies['missing_container_id'] ?? [], 'container_no'),
                array_column($anomalies['missing_position'] ?? [], 'container_no'),
                array_column($anomalies['duplicate_positions'] ?? [], 'duplicate_container'),
                array_column($anomalies['missing_weight'] ?? [], 'container_no')  // ✅ TAMBAHKAN INI
            ),
            0, 5
        )
    ]);
    
    return $anomalies;
}

private function classifyAnomalySeverity($containerAnomalies)
{
    // ✅ CRITICAL anomalies that BLOCK export
    $criticalTypes = [
        'duplicate_positions',
        'duplicate_container_ids', 
        'missing_container_id',
        'invalid_bay_parity'
    ];
    
    // ✅ WARNING anomalies that ALLOW export (tapi perlu diperhatikan)
    $warningTypes = [
        'empty_overweight',
        'empty_underweight',
        'status_weight_mismatch',
        'unknown_status_heavy',
        'full_overload',
        'missing_position',
        'invalid_position',
        'missing_weight'
    ];
    
    $criticalCount = 0;
    $warningCount = 0;
    
    foreach ($criticalTypes as $type) {
        $criticalCount += count($containerAnomalies[$type] ?? []);
    }
    
    foreach ($warningTypes as $type) {
        $warningCount += count($containerAnomalies[$type] ?? []);
    }
    
    return [
        'critical_count' => $criticalCount,
        'warning_count' => $warningCount,
        'critical_types' => $criticalTypes,
        'warning_types' => $warningTypes
    ];
}
    private function getContainerType($container)
{
    // Check reefer first
    if ($container['is_reefer'] ?? false) {
        return 'Reefer';
    }
    
    // Check ISO type
    $isoType = strtoupper($container['iso_type'] ?? '');
    if (strlen($isoType) >= 3) {
        $typeChar = substr($isoType, 2, 1);
        
        // ISO 6346 standard type codes
        if (in_array($typeChar, ['0', '1', '2', '3'])) return 'Dry';
        if (in_array($typeChar, ['4', '5', '6'])) return 'Reefer';
        if (in_array($typeChar, ['7', '8'])) return 'TK'; // Tank
        if ($typeChar === 'P') return 'FR'; // Flat Rack
        if ($typeChar === 'U') return 'OT'; // Open Top
        if ($typeChar === '9') return 'HC'; // High Cube variant
    }
    
    // Check jenis field
    $jenis = strtolower($container['jenis'] ?? '');
    if ($jenis === 'reefer') return 'Reefer';
    if ($jenis === 'tank') return 'TK';
    if ($jenis === 'flat') return 'FR';
    if ($jenis === 'open_top') return 'OT';
    
    // Check type_group field
    $typeGroup = strtoupper($container['type_group'] ?? '');
    if ($typeGroup === 'RF') return 'Reefer';
    if ($typeGroup === 'TK') return 'TK';
    if ($typeGroup === 'FL') return 'FR';
    if ($typeGroup === 'OT') return 'OT';
    
    // Default to Dry
    return 'Dry';
}


private function calculateAnomalySeverity($actualWeight, $referenceWeight, $type)
{
    if ($type === 'overweight') {
        $deviation = ($actualWeight - $referenceWeight) / $referenceWeight;
        if ($deviation > 0.5) return 'critical';
        if ($deviation > 0.2) return 'high';          
        if ($deviation > 0.1) return 'medium';        
        return 'low';
    } elseif ($type === 'underweight') {
        $deviation = ($referenceWeight - $actualWeight) / $referenceWeight;
        if ($deviation > 0.8) return 'critical';      
        if ($deviation > 0.5) return 'high';          
        if ($deviation > 0.3) return 'medium';        
        return 'low';
    }
    return 'unknown';
}

public function anomalyReport()
{
    $containers = session('containers', []);
    $containerAnomalies = session('container_anomalies', []);
    
    if (empty($containers)) {
        return redirect()->route('baplie.management')->with('error', 'No container data found. Please upload BAPLIE file first.');
    }
    
    // If no anomalies in session, calculate them
    if (empty($containerAnomalies)) {
        $containerAnomalies = $this->calculateContainerAnomalies($containers);
        session()->put('container_anomalies', $containerAnomalies);
    }
    
    return view('container_anomaly_report', compact('containerAnomalies', 'containers'));
}

public function exportEdi()
{
    $voyageData = session()->get('voyage');
    $containers = session()->get('containers', []);

    if (!$voyageData) {
        return redirect()->back()->with('error', 'Data voyage tidak ditemukan di session.');
    }

    // ✅ VALIDASI 1: Cek ada container atau tidak
    if (empty($containers)) {
        return redirect()->back()->with('error', 'Tidak ada container data. Silakan upload BAPLIE file terlebih dahulu.');
    }
    // ✅ VALIDASI 2: Cek CRITICAL ANOMALIES dari session
    $containerAnomalies = session('container_anomalies', []);
    
    $criticalAnomalies = [
        'duplicate_positions' => $containerAnomalies['summary']['duplicate_positions_count'] ?? 0,
        'duplicate_ids' => $containerAnomalies['summary']['duplicate_ids_count'] ?? 0,
        'missing_ids' => $containerAnomalies['summary']['missing_id_count'] ?? 0,
    ];
    
    $totalCritical = array_sum($criticalAnomalies);
    
    //  BLOCK EXPORT jika ada critical anomalies
    if ($totalCritical > 0) {
        $errorMessages = [];
        $details = [];
        
        if ($criticalAnomalies['duplicate_positions'] > 0) {
            $errorMessages[] = "• {$criticalAnomalies['duplicate_positions']} duplikat posisi (Bay-Row-Tier)";
            
            // Ambil detail duplikat positions
            $dupPositions = $containerAnomalies['duplicate_positions'] ?? [];
            foreach (array_slice($dupPositions, 0, 3) as $dup) {
                $details[] = "  - Posisi {$dup['position']}: {$dup['first_container']} & {$dup['duplicate_container']}";
            }
            if (count($dupPositions) > 3) {
                $details[] = "  ... dan " . (count($dupPositions) - 3) . " lainnya";
            }
        }
        
        if ($criticalAnomalies['duplicate_ids'] > 0) {
            $errorMessages[] = "• {$criticalAnomalies['duplicate_ids']} duplikat nomor container";
            
            // Ambil detail duplikat IDs
            $dupIds = $containerAnomalies['duplicate_container_ids'] ?? [];
            foreach (array_slice($dupIds, 0, 3) as $dup) {
                $details[] = "  - Container {$dup['container_no']}: muncul di index {$dup['first_occurrence_index']} & {$dup['duplicate_index']}";
            }
            if (count($dupIds) > 3) {
                $details[] = "  ... dan " . (count($dupIds) - 3) . " lainnya";
            }
        }
        
        if ($criticalAnomalies['missing_ids'] > 0) {
            $errorMessages[] = "• {$criticalAnomalies['missing_ids']} container tanpa ID/nomor invalid";
        }
        
        Log::warning(' Export EDI blocked - critical anomalies detected', [
            'duplicate_positions' => $criticalAnomalies['duplicate_positions'],
            'duplicate_ids' => $criticalAnomalies['duplicate_ids'],
            'missing_ids' => $criticalAnomalies['missing_ids'],
            'total_critical' => $totalCritical
        ]);
        
        $errorMessage = " EXPORT DIBLOKIR - Ditemukan Masalah Critical:\n\n" . 
                       implode("\n", $errorMessages);
        
        if (!empty($details)) {
            $errorMessage .= "\n\nContoh masalah:\n" . implode("\n", $details);
        }
        
        $errorMessage .= "\n\n💡 Solusi: Gunakan tombol 'Anomalies' untuk melihat dan memperbaiki masalah ini sebelum export.";
        
        return redirect()->back()
            ->with('error', $errorMessage)
            ->with('export_blocked', true);
    }
    $invalidBayParity = $containerAnomalies['invalid_bay_parity'] ?? [];

    if (!empty($invalidBayParity)) {
        $countInvalid = count($invalidBayParity);
        $examples = array_slice($invalidBayParity, 0, 3);

        $errorMessage = "⚠️ EXPORT DIBLOKIR - Ditemukan {$countInvalid} container dengan bay tidak sesuai aturan ganjil/genap:\n\n";

        foreach ($examples as $anomaly) {
            $bay = $anomaly['bay'] ?? '?';
            $size = $anomaly['size'] ?? '?';
            $containerNo = $anomaly['container_no'] ?? 'UNKNOWN';
            $errorMessage .= "• {$containerNo} (Bay {$bay}, Size {$size})\n";
        }

        if ($countInvalid > 3) {
            $errorMessage .= "... dan " . ($countInvalid - 3) . " lainnya\n";
        }

        $errorMessage .= "\n💡 Solusi: Sesuaikan bay sesuai aturan — 20ft di bay ganjil, 40/45ft di bay genap.";

        Log::warning('Export EDI blocked - invalid bay parity detected', [
            'total_invalid' => $countInvalid,
            'sample' => $examples
        ]);

        return redirect()->back()
            ->with('error', $errorMessage)
            ->with('export_blocked', true);
    }



    // ✅ VALIDASI 3: Cek semua container punya ID dan position
    $containersWithIssues = [];
    $validContainers = [];

    foreach ($containers as $index => $container) {
        $containerNo = trim($container['container_no'] ?? '');
        
        // Skip summary rows
        if (in_array($containerNo, ['DRY FULL', 'MTY', 'DANGEROUS CARGO', 'REEFER', 'OVER DIMENSION/UC', 'TOTAL'])) {
            continue;
        }
        
        if (stripos($containerNo, 'Weight') !== false || stripos($containerNo, 'POD') !== false) {
            continue;
        }

        // ✅ VALIDASI : Container ID harus ada dan valid
        $hasValidContainerId = !empty(trim($containerNo)) && strtoupper(trim($containerNo)) !== 'UNKNOWN';


        if (!$hasValidContainerId) {
            $containersWithIssues[] = [
                'index' => $index,
                'container_no' => $containerNo ?: 'KOSONG',
                'issue' => 'Container ID kosong atau invalid',
                'bay' => '',
                'row' => '',
                'tier' => ''
            ];
            continue;
        }

        // Check position
        $bay = trim($container['bay'] ?? '');
        $row = trim($container['row'] ?? '');
        $tier = trim($container['tier'] ?? '');

       $hasValidPosition = $bay !== '' && $row !== '' && $tier !== '';

        if ($hasValidPosition) {
            $validContainers[] = $container;
        } else {
            $containersWithIssues[] = [
                'index' => $index,
                'container_no' => $containerNo,
                'issue' => 'Position (Bay-Row-Tier) kosong',
                'bay' => $bay ?: 'KOSONG',
                'row' => $row ?: 'KOSONG',
                'tier' => $tier ?: 'KOSONG'
            ];
        }
    }

    // ✅ VALIDASI 4: Jika ada container dengan issue, tolak export
    if (!empty($containersWithIssues)) {
        Log::warning('Export EDI blocked - containers with issues:', [
            'total_with_issues' => count($containersWithIssues),
            'sample' => array_slice($containersWithIssues, 0, 10)
        ]);

        // Hitung jumlah per issue
        $issueCount = [
            'kosong_id' => count(array_filter($containersWithIssues, fn($c) => strpos($c['issue'], 'ID') !== false)),
            'kosong_position' => count(array_filter($containersWithIssues, fn($c) => strpos($c['issue'], 'Position') !== false))
        ];

        $errorMessage = "⚠️ Tidak dapat export EDI - Ada data yang tidak lengkap:\n\n";
        if ($issueCount['kosong_id'] > 0) {
            $errorMessage .= "• {$issueCount['kosong_id']} container dengan ID kosong/invalid\n";
        }
        if ($issueCount['kosong_position'] > 0) {
            $errorMessage .= "• {$issueCount['kosong_position']} container dengan Position (Bay-Row-Tier) kosong\n";
        }
        $errorMessage .= "\nSilakan lengkapi data tersebut sebelum export.";

        return redirect()->back()
            ->with('error', $errorMessage)
            ->with('containers_with_issues', $containersWithIssues);
    }

    // ✅ VALIDASI 5: Pastikan ada container yang valid untuk di-export
    if (empty($validContainers)) {
        return redirect()->back()->with('error', 'Tidak ada container yang lengkap untuk di-export. Silakan lengkapi ID dan Position semua container terlebih dahulu.');
    }

    Log::info('Export EDI - Validation passed', [
        'total_containers' => count($containers),
        'valid_for_export' => count($validContainers),
        'with_issues' => count($containersWithIssues)
    ]);

    $originalVoyageData = session('original_voyage', []);

    // Jika original_voyage kosong (edge case), fallback ke voyage biasa
    if (empty($originalVoyageData)) {
        Log::warning('⚠️ original_voyage not found in session, using current voyage data');
        $originalVoyageData = session('voyage', []);
    }

    Log::info('📄 EDI Export - Using voyage data:', [
        'source' => !empty(session('original_voyage')) ? 'original_voyage' : 'current_voyage',
        'vessel_name' => $originalVoyageData['vessel_name'] ?? 'N/A',
        'voyage_no' => $originalVoyageData['voyage_no'] ?? 'N/A',
        'port_of_departure' => $originalVoyageData['port_of_departure'] ?? 'N/A',
        'port_of_discharge' => $originalVoyageData['port_of_discharge'] ?? 'N/A',
    ]);

    // Extract voyage header fields dari BAPLIE asli
    $sender = $originalVoyageData['sender'] ?? 'SENDER';
    $recipient = $originalVoyageData['recipient'] ?? 'RECIPIENT';
    $interchangeRef = $originalVoyageData['interchange_control_ref'] ?? '1';
    $messageRef = $originalVoyageData['message_reference_number'] ?? '1';
    $documentName = $originalVoyageData['document_name'] ?? 'BAPLIE';
    $messageFunction = $originalVoyageData['message_function'] ?? '9';
    $associationCode = $originalVoyageData['association_code'] ?? 'SMDG20';
    $voyageNo = $originalVoyageData['voyage_no'] ?? '';
    $carrierCode = $originalVoyageData['carrier_code'] ?? '';
    $callSign = $originalVoyageData['call_sign'] ?? '';
    $vesselName = $originalVoyageData['vessel_name'] ?? '';
    $portOfDeparture = $originalVoyageData['port_of_departure'] ?? '';
    $portOfDischarge = $originalVoyageData['port_of_discharge'] ?? '';
    $now = Carbon::now();
    $originalUnb = $originalVoyageData['interchange_datetime'] 
        ?? $originalVoyageData['unb_timestamp'] 
        ?? null;

    $originalDtm137 = $originalVoyageData['document_datetime'] 
        ?? $originalVoyageData['dtm_137'] 
        ?? null;

    $originalDtm178 = $originalVoyageData['departure_datetime'] 
        ?? $originalVoyageData['dtm_178'] 
        ?? null;

    // Gunakan dari file asli kalau tersedia, kalau gak ada fallback ke waktu server
    $unbTimestamp = $originalUnb ?: $now->format('ymd:Hi');
    $dtm137 = $originalDtm137 ?: $now->format('YmdHi');
    $dtm178 = $originalDtm178 ?: null; // optional

    // Mulai buat header EDI
    $edi  = "UNB+UNOA:2+{$sender}+{$recipient}+{$unbTimestamp}+{$interchangeRef}'\n";
    $edi .= "UNH+{$messageRef}+BAPLIE:D:95B:UN:{$associationCode}'\n";
    $edi .= "BGM++{$interchangeRef}+{$messageFunction}'\n";
    $edi .= "DTM+137:{$dtm137}:203'\n";

    // Transport details (TDT dan LOC)
    $edi .= "TDT+20+{$voyageNo}+++{$carrierCode}:172:20+++{$callSign}:103::{$vesselName}'\n";
    $edi .= "LOC+5+{$portOfDeparture}:139:6'\n";

    if (!empty($portOfDischarge)) {
        $edi .= "LOC+61+{$portOfDischarge}:139:6'\n";
    }

    // Tambahkan DTM+178 kalau ada departure time asli
    if ($dtm178) {
        $edi .= "DTM+178:{$dtm178}:203'\n";
    } elseif (!empty($originalVoyageData['departure_date'])) {
        // fallback aman kalau format departure_date masih string tanggal
        try {
            $departure = Carbon::parse($originalVoyageData['departure_date'])->format('ymdHi');
            $edi .= "DTM+178:{$departure}:203'\n";
        } catch (\Exception $e) {
            Log::warning("Departure date parsing error in EDI export: " . $e->getMessage());
        }
    }


  
        foreach ($validContainers as $c) {
        $containerNo = trim($c['container_no']);
        
        // ✅ 1. LOC+147 - Posisi container
        $edi .= "LOC+147+{$this->formatPosition($c)}::5'\n";
        
        // ✅ 2. MEA - Weight (VGM atau WT)
        $weightKg = $c['weight_kg'] ?? 0;
        if ($weightKg > 0) {
            $formattedWeight = number_format($weightKg, 0, '.', '');
            // ✅ PRESERVE original MEA type code dari BAPLIE
            $weightType = $c['original_mea_type_code'] ?? (!empty($c['verified_gross_mass']) ? 'VGM' : 'WT');
            $edi .= "MEA+{$weightType}++KGM:{$formattedWeight}'\n";
        }
        
        // ✅ 3. TMP - Temperature (SETELAH MEA, SEBELUM LOC+9!)
        if (($c['is_reefer'] ?? false) && isset($c['set_temperature']) && is_numeric($c['set_temperature'])) {
            $temp = $c['set_temperature'];
            $unit = $c['temperature_unit'] ?? 'CEL';
            
            // Format temperature dengan 1 decimal
            $formattedTemp = number_format($temp, 1, '.', '');
            $edi .= "TMP+2+{$formattedTemp}:{$unit}'\n";
        }
        
        // ✅ 4. RNG - Temperature Range (jika ada, SETELAH TMP)
        if (($c['is_reefer'] ?? false) && !empty($c['temperature_range'])) {
            $range = $c['temperature_range'];
            $unit = $range['unit'] ?? 'CEL';
            $min = isset($range['min']) ? number_format($range['min'], 1, '.', '') : '';
            $max = isset($range['max']) ? number_format($range['max'], 1, '.', '') : '';
            
            if (!empty($min) && !empty($max)) {
                $edi .= "RNG+5+{$unit}:{$min}:{$max}'\n";
            }
        }
        
        // ✅ 5. LOC+9 - Port of Loading
        $polLocode = $c['pol_locode'] ?? '';
        if (!empty($polLocode)) {
            $edi .= "LOC+9+{$polLocode}'\n";
        }
        
        // ✅ 6. LOC+11 - Port of Discharge
        $podLocode = $c['pod_locode'] ?? '';
        if (!empty($podLocode)) {
            $edi .= "LOC+11+{$podLocode}'\n";
        }
        
        // ✅ 7. LOC+76 - Inland Location (OPSIONAL)
        $inlandLocation = $c['inland_location_76'] ?? '';
        if (!empty($inlandLocation)) {
            $edi .= "LOC+76+{$inlandLocation}'\n";
        }

        // ✅ 8. LOC+83 - Delivery Location
        $deliveryLocode = $c['delivery_locode'] ?? '';
        if (!empty($deliveryLocode)) {
            $edi .= "LOC+83+{$deliveryLocode}'\n";
        }

        // ✅ 9. RFF+BM - B/L Reference
        $blNo = $c['bl_no'] ?? '';
        if (!empty($blNo)) {
            $edi .= "RFF+BM:{$blNo}'\n";
        }
        
        // ✅ 9. EQD - Equipment details
        $isoType = $c['iso_type'] ?? '';
        $status = $c['status'] ?? $c['status_code'] ?? '5';
        $edi .= "EQD+CN+{$containerNo}+{$isoType}+++{$status}'\n";
        
        // ✅ 10. FTX+REF - Reefer Instructions (OPSIONAL, setelah EQD sebelum NAD)
        if (($c['is_reefer'] ?? false) && !empty($c['reefer_instructions'])) {
            $instruction = str_replace("'", '', $c['reefer_instructions']); // Remove quotes
            $edi .= "FTX+REF+++{$instruction}'\n";
        }
        
        // ✅ 11. NAD+CA - Operator (TERAKHIR!)
        // ✅ PRESERVE original NAD format dari BAPLIE (misal: MAE:172:ZZZ)
        $nadFormat = $c['original_nad_format'] ?? null;
        $operatorCode = $c['operator_code'] ?? null;
        $defaultNad = session('default_nad');

        if (!empty($nadFormat)) {
            // Gunakan original NAD format dari BAPLIE
            $edi .= "NAD+CA+{$nadFormat}'\n";
        } elseif (!empty($operatorCode)) {
            // Fallback: gunakan operator code dengan default format
            $edi .= "NAD+CA+{$operatorCode}:172:20'\n";
        } elseif (!empty($defaultNad)) {
            // Fallback: gunakan default NAD dengan default format
            $edi .= "NAD+CA+{$defaultNad}:172:20'\n";
        }
        
        // ✅ 13. FTX+AAY - Additional info (OPSIONAL, setelah NAD jika ada)
        // ✅ FIX: Preserve full FTX data (tidak hardcode SM2)
        if (!empty($c['additional_info'])) {
            $info = str_replace("'", '', $c['additional_info']);
            // additional_info sudah berisi format lengkap: SM2+data_panjang
            // Jadi tinggal output: FTX+AAY++{info}'
            $edi .= "FTX+AAY++{$info}'\n";
        }
    }
        
    // Closing segments
    $segmentCount = substr_count($edi, "'");
    $edi .= "UNT+{$segmentCount}+{$messageRef}'\n";
    $edi .= "UNZ+1+{$interchangeRef}'\n";

    Log::info('EDI export successful', [
        'total_containers_in_system' => count($containers),
        'containers_exported' => count($validContainers),
        'containers_with_issues' => count($containersWithIssues),
        'segment_count' => $segmentCount
    ]);

    //  Generate filename from original uploaded file
    $originalFilename = session('original_baplie_filename');

    if ($originalFilename) {
        // Remove extension
        $nameWithoutExt = pathinfo($originalFilename, PATHINFO_FILENAME);
        $extension = pathinfo($originalFilename, PATHINFO_EXTENSION) ?: 'edi';
        
        // Format: original_updated.edi
        $filename = $nameWithoutExt . "_updated." . $extension;
        
        Log::info('Using original filename for export', [
            'original' => $originalFilename,
            'export_as' => $filename
        ]);
    } else {
        // Fallback jika tidak ada original filename
        $voyageNo = session('voyage.voyage_no', 'export');
        $now = \Carbon\Carbon::now();
        $filename = "baplie_" . ($voyageNo ?: 'export') . "_updated_" . $now->format('YmdHis') . ".edi";
        
        Log::warning('Original filename not found, using fallback', [
            'fallback_filename' => $filename
        ]);
    }

    // ✅ Return EDI content as downloadable file
    return response($edi)
        ->header('Content-Type', 'text/plain')
        ->header('Content-Disposition', "attachment; filename=\"{$filename}\"");
    }
   
    private function formatPosition($container)
    {
        $bay = str_pad($container['bay'] ?? '', 3, '0', STR_PAD_LEFT);
        $row = str_pad($container['row'] ?? '', 2, '0', STR_PAD_LEFT);
        $tier = str_pad($container['tier'] ?? '', 2, '0', STR_PAD_LEFT);
        
        return "{$bay}{$row}{$tier}";
    }
    public function reeferReport()
    {
        $containers = session('containers', []);
        $reeferContainers = array_filter($containers, function($container) {
            return $container['is_reefer'] ?? false;
        });
        
        if (empty($reeferContainers)) {
            return redirect()->back()->with('info', 'No reefer containers found in current data.');
        }
        
        $reeferStats = $this->calculateReeferStatistics($reeferContainers);
        
        return view('reefer_report', compact('reeferContainers', 'reeferStats'));
    }

    // Helper baru untuk reefer report (KOREKSI KONVERSI SUHU)
    private function calculateReeferStatistics($reeferContainers)
    {
        $stats = [
            'total' => count($reeferContainers),
            'with_temp_set' => 0,
            'temp_ranges' => [],
            'avg_temp' => null,
            'commodities' => []
        ];
        
        $temperaturesCelcius = []; // Menggunakan array yang sudah dikonversi
        
        foreach ($reeferContainers as $container) {
            if (!empty($container['set_temperature'])) {
                $stats['with_temp_set']++;
                
                $temp = $container['set_temperature'];
                $unit = $container['temperature_unit'] ?? 'CEL';

                // *** PERBAIKAN: Konversi ke Celsius sebelum dihitung ***
                $tempCelcius = $this->convertToCelcius($temp, $unit);
                $temperaturesCelcius[] = $tempCelcius;
            }
        }
        
        if (!empty($temperaturesCelcius)) {
            $stats['avg_temp'] = round(array_sum($temperaturesCelcius) / count($temperaturesCelcius), 1);
        }
        
        return $stats;
    }


  public function index()
{
    Log::info('=== CONTAINER COUNT DEBUG START ===');

    $containers = session('containers', []);
    $voyage = session('voyage', []);
    $locations = session('locations', []);
    $weightDebug = session('weight_debug', []);
    $statusBreakdown = session('status_breakdown', []);
    $jenisCounts = session('jenis_breakdown', []);
    $sizeBreakdown = session('size_breakdown', []);
    $reeferStats = session('reefer_statistics', []);

    Log::info('Initial data:', [
        'containers_from_session' => count($containers),
        'status_breakdown_from_session' => $statusBreakdown,
        'sample_container_status' => !empty($containers) ? [
            'container_no' => $containers[0]['container_no'] ?? 'N/A',
            'status' => $containers[0]['status'] ?? 'N/A',
            'status_code' => $containers[0]['status_code'] ?? 'N/A',
            'status_mapped' => $containers[0]['status_mapped'] ?? 'N/A'
        ] : 'no_containers'
    ]);

    if (empty($containers)) {
        return redirect()->route('baplie.upload')->with('warning', 'No BAPLIE data found. Please upload a file first.');
    }

    // ===== CRITICAL FIX: Add container count tracking =====
    $containerAnomalies = session('container_anomalies', null);
    $lastContainerCount = session('last_container_count', 0);
    $currentContainerCount = count($containers);
    
    // Create container hash for detecting data changes (not just count)
    $currentHash = md5(json_encode(array_column($containers, 'container_no')));
    $lastHash = session('last_container_hash', '');
    
    // Determine if recalculation is needed
    $shouldRecalculate = false;
    $recalcReason = '';
    
    if (empty($containerAnomalies) || !isset($containerAnomalies['summary'])) {
        $shouldRecalculate = true;
        $recalcReason = 'Anomalies missing or invalid structure';
    } elseif ($currentContainerCount !== $lastContainerCount) {
        $shouldRecalculate = true;
        $recalcReason = sprintf('Container count changed: %d → %d', $lastContainerCount, $currentContainerCount);
    } elseif ($currentHash !== $lastHash) {
        $shouldRecalculate = true;
        $recalcReason = 'Container data changed (different containers)';
    }
    
    if ($shouldRecalculate) {
        $containerAnomalies = $this->calculateContainerAnomalies($containers);
        session()->put('container_anomalies', $containerAnomalies);
        session()->put('last_container_hash', md5(json_encode($containers)));

        Log::warning(' Recalculating anomalies:', [
            'reason' => $recalcReason,
            'current_count' => $currentContainerCount,
            'last_count' => $lastContainerCount,
            'hash_changed' => $currentHash !== $lastHash
        ]);
        
        $containerAnomalies = $this->calculateContainerAnomalies($containers);
        session()->put('container_anomalies', $containerAnomalies);
        session()->put('last_container_count', $currentContainerCount);
        session()->put('last_container_hash', $currentHash);
        
        Log::info(' Anomalies recalculated and saved:', [
            'total_anomalies' => $containerAnomalies['summary']['total_anomalies'] ?? 0,
            'empty_overweight' => count($containerAnomalies['empty_overweight'] ?? []),
            'duplicate_positions' => count($containerAnomalies['duplicate_positions'] ?? []),
            'status_mismatch' => count($containerAnomalies['status_weight_mismatch'] ?? []),
            'full_overload' => count($containerAnomalies['full_overload'] ?? []),
        ]);
    } else {
        Log::info('Using cached anomalies from session:', [
            'total_anomalies' => $containerAnomalies['summary']['total_anomalies'] ?? 0,
            'container_count' => $currentContainerCount,
            'hash_match' => $currentHash === $lastHash
        ]);
    }

    $totalContainers = count($containers);
    $validBreakdown = $this->isValidStatusBreakdown($statusBreakdown, $containers);

    if (!$validBreakdown) {
        Log::warning('Status breakdown invalid, recalculating...');
        
        $manualBreakdown = [
            '5' => ['count' => 0, 'weight_kg' => 0],
            '4' => ['count' => 0, 'weight_kg' => 0],
            'U' => ['count' => 0, 'weight_kg' => 0],
        ];
        
        foreach ($containers as $index => $container) {
            //  Use unified normalization
            $statusCode = $this->normalizeStatusToCode($container['status_code'] ?? $container['status'] ?? 'U');
            $weight = floatval($container['weight_kg'] ?? 0);
            
            if ($index < 3) {
                Log::info("Container #$index status processing:", [
                    'container_no' => $container['container_no'] ?? 'N/A',
                    'raw_status' => $container['status'] ?? 'null',
                    'status_code_field' => $container['status_code'] ?? 'null',
                    'normalized_code' => $statusCode,
                    'status_text' => $this->statusCodeToText($statusCode)
                ]);
            }
            
            if (isset($manualBreakdown[$statusCode])) {
                $manualBreakdown[$statusCode]['count']++;
                if ($weight > 0) {
                    $manualBreakdown[$statusCode]['weight_kg'] += $weight;
                }
            }
        }
        
        $statusBreakdown = $manualBreakdown;
        session()->put('status_breakdown', $manualBreakdown);
        
    }

    // Extract final counts
    $countFull = $statusBreakdown['5']['count'] ?? 0;
    $countEmpty = $statusBreakdown['4']['count'] ?? 0;
    $countUnknown = $statusBreakdown['U']['count'] ?? 0;

    // === CONTAINER POSITION ANALYSIS ===
    $containersWithoutPositionCount = 0;
    $containersWithPositionCount = 0;

    foreach ($containers as $container) {
        $bay = $container['bay'] ?? '';
        $row = $container['row'] ?? '';
        $tier = $container['tier'] ?? '';

        if (empty($bay) || empty($row) || empty($tier) || 
            ($bay === '000' && $row === '00' && $tier === '00') ||
            ($bay === '0' && $row === '0' && $tier === '0')) {
            $containersWithoutPositionCount++;
        } else {
            $containersWithPositionCount++;
        }
    }

    // === UPDATE WEIGHT DEBUG ===
    $totalWeightTons = ($weightDebug['total_weight_tons'] ?? 0); 

    $weightDebug = [
        'containers_with_position' => $containersWithPositionCount,
        'containers_without_position' => $containersWithoutPositionCount,
        'total_weight_tons' => $totalWeightTons,
    ];

    session()->put('weight_debug', $weightDebug);

    // Size breakdown validation
    if (empty($sizeBreakdown)) {
        Log::warning('Size breakdown empty, might need recalculation');
    }

    // Create filteredSizeCounts
    $filteredSizeCounts = [];
    $allowedSizes = ["20'", "40'", "45'"];
    foreach ($sizeBreakdown as $size => $data) {
        if (in_array($size, $allowedSizes)) {
            $filteredSizeCounts[$size] = is_array($data) ? ($data['count'] ?? 0) : $data;
        }
    }
    // === FIX: Ensure totalWeight is defined ===
    if (!isset($totalWeight)) {
    // Coba ambil dari session kalau pernah disimpan sebelumnya
    $totalWeight = session('total_weight', 0);

    // Kalau nggak ada di session, hitung manual dari statusBreakdown
    if (!$totalWeight && !empty($statusBreakdown)) {
        $totalWeight = collect($statusBreakdown)
            ->sum(fn($s) => $s['weight_kg'] ?? 0);
    }

    // Simpan ke session biar persist
    session(['total_weight' => $totalWeight]);
}


    return view('baplie_management', compact(
        'containers',
        'voyage',
        'locations',
        'weightDebug',
        'sizeBreakdown',
        'filteredSizeCounts',
        'jenisCounts',
        'countFull',
        'countEmpty',
        'countUnknown',
        'statusBreakdown',
        'totalWeight',
        'reeferStats',
        'containerAnomalies'
    ));
}
    private function isValidStatusBreakdown($statusBreakdown, $containers)
    {
        if (empty($statusBreakdown) || !is_array($statusBreakdown)) {
            return false;
        }

        // Cek apakah ada key yang required
        $requiredKeys = ['5', '4', 'U'];
        foreach ($requiredKeys as $key) {
            if (!isset($statusBreakdown[$key]) || !isset($statusBreakdown[$key]['count'])) {
                return false;
            }
        }

        $totalFromBreakdown = 0;
        foreach ($requiredKeys as $status) {
            $count = $statusBreakdown[$status]['count'] ?? 0;
            if (!is_numeric($count) || $count < 0) {
                return false;
            }
            $totalFromBreakdown += $count;
        }

        $totalContainers = count($containers);
        
        // Valid jika total breakdown sama dengan total container
        return ($totalFromBreakdown === $totalContainers && $totalContainers > 0);
    }
    /**
     * Helper method untuk mendapatkan ukuran container
     */
    private function getContainerSize($container)
    {
        // Prioritaskan field 'size' dari parser
        $sizeField = $container['size'] ?? '';
        
        if (!empty($sizeField) && $sizeField !== 'Unknown Size' && $sizeField !== 'Unknown') {
            $size = strtoupper(trim($sizeField));
            if (strpos($size, '20') !== false) return "20'";
            if (strpos($size, '40') !== false) return "40'";
            if (strpos($size, '45') !== false) return "45'";
        }
        
        // Fallback ke parsing ISO type
        $isoType = $container['iso_type'] ?? '';
        if (!empty($isoType) && strlen($isoType) >= 2) {
            $firstChar = substr($isoType, 0, 1);
            $secondChar = substr($isoType, 1, 1);
            
            if ($firstChar == '2') return "20'";
            if ($firstChar == '4') return "40'";
            if ($firstChar == '4' && $secondChar == '5') return "45'";
            if ($firstChar == 'L') return "45'";
        }
        
        return 'Unknown';
    }
    
   private function mapContainerStatus($statusCode)
    {
        return $this->statusCodeToText($statusCode); 
    }
    
    private function determineJenisFromContainer($container)
    {
        $isoType = $container['iso_type'] ?? '';
        $status = $container['status'] ?? '';
        
        if (strlen($isoType) >= 3) {
            $typeChar = substr($isoType, 2, 1);
            
            if (in_array($typeChar, ['0', '1', '2', '3'])) {
                return ($status === 'E') ? 'empty' : 'dry';
            } elseif (in_array($typeChar, ['4', '5', '6'])) {
                return 'reefer';
            } elseif (in_array($typeChar, ['7', '8'])) {
                return 'tank';
            } elseif ($typeChar === '9') {
                return 'flat';
            }
        }
        
        // Fallback berdasarkan status
        if ($status === 'E') {
            return 'empty';
        } elseif (in_array($status, ['F', 'L', '5'])) {
            return 'dry';
        }
        
        return 'unknown';
        
    }
  public function deleteContainer(Request $request, $index)
{
    // Debug logging
    Log::info('🗑️ DELETE REQUEST RECEIVED', [
        'method' => $request->method(),
        'url' => $request->fullUrl(),
        'index' => $index,
        'ip' => $request->ip()
    ]);

    try {
        // ✅ FIX: Convert to integer
        $index = (int) $index;
        
        
        $containers = session('containers', []);
        
        // Validation
        if (!is_array($containers)) {
            Log::error(' Containers session is not an array');
            return response()->json([
                'success' => false, 
                'message' => 'Invalid session data'
            ], 500);
        }
        
        if ($index < 0 || $index >= count($containers)) {
            Log::warning('❌ Container index out of bounds', [
                'requested_index' => $index,
                'max_index' => count($containers) - 1
            ]);
            return response()->json([
                'success' => false, 
                'message' => "Container not found at index {$index}"
            ], 404);
        }
        
        // tore deleted container info BEFORE deletion
        $deletedContainer = $containers[$index];
        $deletedContainerNo = $deletedContainer['container_no'] ?? 'Unknown';
        
        //  Remove container using unset
        unset($containers[$index]);
        
        //  Reindex array to prevent gaps
        $containers = array_values($containers);
        
        // CRITICAL: Update session IMMEDIATELY
        session()->put('containers', $containers);
        session()->put('last_container_count', count($containers));
        session()->put('last_container_hash', md5(json_encode(array_column($containers, 'container_no'))));
        
        //  Save session to ensure persistence
        session()->save();
        
        // Recalculate statistics
        try {
            $this->recalculateBreakdowns();
        } catch (\Exception $e) {
            Log::error(' Failed to recalculate breakdowns: ' . $e->getMessage());
        }
        
        return response()->json([
            'success' => true,
            'message' => 'Container deleted successfully',
            'deleted_container_no' => $deletedContainerNo,
            'remaining_count' => count($containers),
            'session_updated' => true
        ]);
        
    } catch (\Exception $e) {
        Log::error('❌ Delete container error', [
            'index' => $index,
            'error' => $e->getMessage(),
            'trace' => $e->getTraceAsString()
        ]);
        
        return response()->json([
            'success' => false,
            'message' => 'Error deleting container: ' . $e->getMessage()
        ], 500);
    }
}
   public function duplicateContainer(Request $request)
{
    try {
        $containers = session('containers', []);
        $indexToDuplicate = (int) $request->input('container_index');
        

        if (!isset($containers[$indexToDuplicate])) {
            return response()->json([
                'success' => false,
                'message' => 'Container not found at index ' . $indexToDuplicate
            ], 404);
        }

        // ✅ PERBAIKAN: Clone container dengan deep copy
        $originalContainer = $containers[$indexToDuplicate];
        $newContainer = $originalContainer; // Array copy
        
        // ✅ Generate unique container number yang lebih baik
        $originalNo = $originalContainer['container_no'] ?? 'TEMP0000000';
        $baseNo = substr($originalNo, 0, 10); // Ambil 10 karakter pertama
        
        // Cari nomor duplikat berikutnya
        $duplicateCount = 1;
        do {
            $newContainerNo = $baseNo . '_DUP' . $duplicateCount;
            $exists = false;
            foreach ($containers as $c) {
                if (($c['container_no'] ?? '') === $newContainerNo) {
                    $exists = true;
                    break;
                }
            }
            if ($exists) {
                $duplicateCount++;
            }
        } while ($exists && $duplicateCount < 100);
        
        $newContainer['container_no'] = $newContainerNo;
        
        // ✅ Reset data yang harus unik/kosong
        $newContainer['status'] = 'E';
        $newContainer['status_code'] = '4';
        $newContainer['status_mapped'] = 'Empty';
        $newContainer['full_empty'] = 'EMPTY';
        $newContainer['weight_kg'] = 0;
        $newContainer['weight_details'] = [];
        
        // ✅ Reset posisi agar tidak duplicate position
        $newContainer['bay'] = '';
        $newContainer['row'] = '';
        $newContainer['tier'] = '';
        $newContainer['location'] = '';
        
        // ✅ Reset seal dan booking
        $newContainer['seal_no'] = '';
        $newContainer['bl_no'] = '';
        $newContainer['booking_no'] = '';
        
        // ✅ Untuk reefer, reset temperature tapi keep settings
        if ($newContainer['is_reefer'] ?? false) {
            $newContainer['set_temperature'] = null;
            $newContainer['temperature_range'] = null;
            // Keep: is_reefer, temperature_unit, reefer_instructions
        }
        
        // ✅ Tambahkan metadata
        $newContainer['updated_from_excel'] = false;
        $newContainer['keterangan'] = 'Duplicated from ' . $originalNo;
        $newContainer['created_at'] = now()->toDateTimeString();
        
        // ✅ Insert SETELAH original container
        array_splice($containers, $indexToDuplicate + 1, 0, [$newContainer]);
        
        // ✅ CRITICAL: Update session
        session()->put('containers', $containers);
        
        // ✅ Recalculate statistics
        $this->recalculateBreakdowns();
        
        
        return response()->json([
            'success' => true,
            'message' => 'Container duplicated successfully',
            'new_container' => $newContainer,
            'new_container_no' => $newContainerNo,
            'new_index' => $indexToDuplicate + 1,
            'original_index' => $indexToDuplicate,
            'total_containers' => count($containers)
        ]);
        
    } catch (\Exception $e) {
        Log::error('❌ Duplicate container error', [
            'error' => $e->getMessage(),
            'trace' => $e->getTraceAsString()
        ]);
        
        return response()->json([
            'success' => false,
            'message' => 'Error: ' . $e->getMessage()
        ], 500);
    }
}

    // Tambahkan di akhir BaplieController.php
    public function bayplan()
{
    $containers = session('containers', []);
    $voyage = session('voyage', []);  // Ambil voyage dari session jika ada
    
    
    if (empty($containers)) {
        return redirect()->route('baplie.management')->with('error', 'No container data found. Please upload BAPLIE file first.');
    }
    
    // Filter hanya positioned containers (punya bay, row, tier valid - bukan kosong)
    $positionedContainers = collect($containers)->filter(function ($container) {
        return !empty($container['bay']) && !empty($container['row']) && !empty($container['tier']);
    });
    
    if ($positionedContainers->isEmpty()) {
        return redirect()->route('baplie.management')->with('warning', 'No positioned containers found. Please assign positions first.');
    }
    
    try {
        
        $containerData = $positionedContainers->map(function ($container) use ($voyage) {
            return [
                'id' => $container['container_no'] ?? 'UNKNOWN',
                'container_number' => $container['container_no'] ?? 'UNKNOWN',
                'bay' => $container['bay'],  
                'row' => $container['row'],
                'tier' => $container['tier'],
                'position' => $container['bay'] . '-' . $container['row'] . '-' . $container['tier'],
                'length' => $this->extractLength($container),
                'status' => $this->mapStatusCodeToText($container['status'] ?? $container['status_code'] ?? $container['full_empty'] ?? 'U'),
                'weight' => intval($container['weight_kg'] ?? $container['weight'] ?? 0),
                'line' => $this->extractLine($container['container_no'] ?? ''),
                'pod' => $container['pod_locode'] ?? $container['pod'] ?? 'UNKNOWN',
                'pol' => $container['pol_locode'] ?? $container['pol'] ?? 'UNKNOWN',
                'iso_type' => $container['iso_type'] ?? '',
                'bl_no' => $container['bl_no'] ?? '',
                'operator_code' => $container['operator_code'] ?? '',
                'imdg' => !empty($container['imdg_class']),
                'reefer' => !empty($container['temperature']) && $container['temperature'] !== '0' || ($container['is_reefer'] ?? false),  // Check temperature atau is_reefer
                'temperature' => $container['set_temperature'] ?? $container['temperature'] ?? null,
                'seal_no' => $container['seal_no'] ?? '',
                'booking_ref' => $container['booking_ref'] ?? '',
                'vessel' => $voyage['vessel_name'] ?? $voyage['vessel'] ?? 'MV DEMO VESSEL',  
                'voyage' => $voyage['voyage_no'] ?? $voyage['voyage'] ?? 'VOYAGE001',
            ];
        })->values()->all();
        
        
    } catch (\Exception $e) {
        Log::error('Error mapping bayplan data:', [
            'error' => $e->getMessage(),
            'trace' => $e->getTraceAsString()
        ]);
        return redirect()->route('baplie.management')->with('error', 'Error processing container data. Please try again.');
    }
    
    // Calculate simple statistics (untuk tampilkan di view jika diperlukan)
    $stats = [
        'total' => count($containers),  
        'positioned' => count($containerData),  
        'unpositioned' => count($containers) - count($containerData),
        'full' => count(array_filter($containerData, fn($c) => $c['status'] === 'Full')),
        'empty' => count(array_filter($containerData, fn($c) => $c['status'] === 'Empty')),
        'imdg' => count(array_filter($containerData, fn($c) => $c['imdg'])),
        'reefer' => count(array_filter($containerData, fn($c) => $c['reefer'])),
        'total_weight' => array_sum(array_map(fn($c) => (int)($c['weight'] ?? 0), $containerData)),
        'average_weight' => count($containerData) > 0 ? round(array_sum(array_map(fn($c) => (int)($c['weight'] ?? 0), $containerData)) / count($containerData), 2) : 0,
    ];
    
    // Bay distribution untuk stats
    $bayDistribution = [];
    foreach ($containerData as $container) {
        $bay = $container['bay'];
        $bayDistribution[$bay] = ($bayDistribution[$bay] ?? 0) + 1;
    }
    ksort($bayDistribution);
    $stats['bay_distribution'] = $bayDistribution;
    
    
    return view('bayplan.index', compact('containerData', 'voyage', 'stats'));  
}

    // Helper methods disesuaikan dengan controller Anda
    private function mapStatusCodeToText($statusCode)
    {
        // Sesuaikan dengan format controller Anda
        $statusCode = strtoupper(trim($statusCode));
        
        $mapping = [
            '5' => 'Full',
            'F' => 'Full', 
            'FULL' => 'Full',
            
            '4' => 'Empty',
            'E' => 'Empty',
            'EMPTY' => 'Empty',
            'MTY' => 'Empty',
            
            'U' => 'Unknown',
            '' => 'Unknown'
        ];
        
        return $mapping[$statusCode] ?? 'Unknown';
    }

    private function extractLength($container)
    {
        // Prioritaskan field 'size' seperti di getContainerSize()
        $size = $container['size'] ?? '';
        if (strpos($size, '20') !== false) return 20;
        if (strpos($size, '40') !== false) return 40;
        if (strpos($size, '45') !== false) return 45;
        
        // Fallback ke ISO type seperti di controller Anda
        $isoType = $container['iso_type'] ?? '';
        if (strlen($isoType) >= 1) {
            $sizeChar = substr($isoType, 0, 1);
            if ($sizeChar === '2') return 20;
            if ($sizeChar === '4') return 40;
            if ($sizeChar === 'L') return 45;
        }
        
        return 20;
    }

    private function extractLine($containerNo)
    {
        return substr($containerNo, 0, 4);
    }
    public function debugSessionAnomaly()
{
    $containers = session('containers', []);
    $containerAnomalies = session('container_anomalies', null);
    $lastCount = session('last_container_count', 'NOT SET');
    $lastHash = session('last_container_hash', 'NOT SET');
    
    $debugData = [
        'session_status' => [
            'containers_count' => count($containers),
            'anomalies_exist' => !empty($containerAnomalies),
            'anomalies_valid' => isset($containerAnomalies['summary']),
            'last_container_count' => $lastCount,
            'last_container_hash' => substr($lastHash, 0, 8) . '...',
        ],
        'anomaly_summary' => $containerAnomalies['summary'] ?? 'NO ANOMALIES IN SESSION',
        'anomaly_details' => [
            'empty_overweight' => count($containerAnomalies['empty_overweight'] ?? []),
            'empty_underweight' => count($containerAnomalies['empty_underweight'] ?? []),
            'status_mismatch' => count($containerAnomalies['status_weight_mismatch'] ?? []),
            'unknown_heavy' => count($containerAnomalies['unknown_status_heavy'] ?? []),
            'full_overload' => count($containerAnomalies['full_overload'] ?? []),
            'duplicate_ids' => count($containerAnomalies['duplicate_container_ids'] ?? []),
            'duplicate_positions' => count($containerAnomalies['duplicate_positions'] ?? []),
        ],
        'sample_anomalies' => [
            'full_overload' => array_slice($containerAnomalies['full_overload'] ?? [], 0, 2),
            'duplicate_positions' => array_slice($containerAnomalies['duplicate_positions'] ?? [], 0, 2),
        ],
        'current_hash' => substr(md5(json_encode(array_column($containers, 'container_no'))), 0, 8),
        'hash_match' => ($lastHash === md5(json_encode(array_column($containers, 'container_no')))),
    ];
    
    
    return response()->json($debugData, 200, [], JSON_PRETTY_PRINT);
}

}