<?php

namespace App\Filament\Imports;

use App\Models\CharacteristicValue;
use App\Models\Item;
use App\Models\Line;
use App\Models\Machine;
use App\Models\Plant;
use App\Models\ProcessOrder;
use App\Models\ProductCharacteristicsMaster;
use App\Models\User;
use Carbon\Carbon;
use Filament\Actions\Imports\Exceptions\RowImportFailedException;
use Filament\Actions\Imports\ImportColumn;
use Filament\Actions\Imports\Importer;
use Filament\Actions\Imports\Models\Import;
use Filament\Facades\Filament;
use Str;

class CharacteristicValueImporter extends Importer
{
    protected static ?string $model = CharacteristicValue::class;

    public static function getColumns(): array
    {
        return [
            ImportColumn::make('plant')
                ->requiredMapping()
                ->exampleHeader('Plant Code')
                ->example('1000')
                ->label('Plant Code')
                ->relationship(resolveUsing: 'code')
                ->rules(['required']),
            ImportColumn::make('line')
                ->requiredMapping()
                ->exampleHeader('Line Name')
                ->example('4 inch pump line')
                ->label('Line Name')
                ->relationship(resolveUsing: 'name')
                ->rules(['required']),
            ImportColumn::make('item')
                ->requiredMapping()
                ->exampleHeader('Item Code')
                ->example('123456')
                ->label('Item Code')
                ->relationship(resolveUsing: 'code')
                ->rules(['required']),
            ImportColumn::make('machine')
                ->requiredMapping()
                ->exampleHeader('Work Center')
                ->example('RMGS09745')
                ->label('Work Center')
                ->relationship(resolveUsing: 'work_center')
                ->rules(['required']),
            ImportColumn::make('process_order')
                ->requiredMapping()
                ->exampleHeader('Process Order')
                ->example('23455256352')
                ->label('Process Order'),
            ImportColumn::make('coil_number')
                ->requiredMapping()
                ->exampleHeader('Coil Number')
                ->example('0')
                ->label('Coil Number'),
            ImportColumn::make('status')
                ->requiredMapping()
                ->exampleHeader('Status')
                ->example('Ok')
                ->label('Status'),
            ImportColumn::make('observed_value')
                ->requiredMapping()
                ->exampleHeader('Observed Value')
                ->example('RAW01234')
                ->label('Observed Value'),
            ImportColumn::make('created_by')
                ->requiredMapping()
                ->exampleHeader('Created By')
                ->example('RAW01234')
                ->label('Created By'),
            ImportColumn::make('created_at')
                ->requiredMapping()
                ->exampleHeader('Created DateTime')
                ->example('01-01-2025 08:00:00')
                ->label('Created DateTime')
                ->rules(['required']),
            ImportColumn::make('updated_at')
                ->requiredMapping()
                ->exampleHeader('Updated DateTime')
                ->example('01-01-2025 08:00:00')
                ->label('Updated DateTime')
                ->rules(['required']),
        ];
    }

    public function resolveRecord(): ?CharacteristicValue
    {
        // return CharacteristicValue::firstOrNew([
        //     // Update existing records, matching them by `$this->data['column_name']`
        //     'email' => $this->data['email'],
        // ]);

        $warnMsg = [];
        $plantId = null;
        $itemId = null;
        $lineId = null;
        $machineId = null;
        // $itemAgainstPlant = null;

        $plantCode = $this->data['plant'];
        $processOrder = trim($this->data['process_order'] ?? '');
        $iCode = trim($this->data['item']);
        $workCenter = trim($this->data['machine']);
        $lineName = trim($this->data['line']);
        $coilNo = trim($this->data['coil_number']);
        $obserVal = trim($this->data['observed_value']);
        $status = trim($this->data['status']);
        $createdBy = trim($this->data['created_by']);

        if ($plantCode == null || $plantCode == '') {
            $warnMsg[] = 'Plant code cannot be empty';
        } elseif ($iCode == null || $iCode == '') {// process_order
            $warnMsg[] = 'Item code cannot be empty';
        } elseif ($processOrder == null || $processOrder == '') {//
            $warnMsg[] = 'Process Order cannot be empty';
        } elseif ($workCenter == null || $workCenter == '') {
            $warnMsg[] = 'Work center cannot be empty';
        } elseif ($lineName == null || $lineName == '') {
            $warnMsg[] = 'Line name cannot be empty';
        } elseif ($coilNo == null || $coilNo == '') {
            $warnMsg[] = 'Coil number cannot be empty';
        } elseif ($obserVal == null || $obserVal == '') {
            $warnMsg[] = 'Observed value cannot be empty';
        } elseif ($status == null || $status == '') {
            $warnMsg[] = 'Status cannot be empty';
        }

        if (Str::length($plantCode) > 0 && (Str::length($plantCode) < 4 || ! is_numeric($plantCode) || ! preg_match('/^[1-9]\d{3,}$/', $plantCode))) {
            $warnMsg[] = 'Invalid plant code found';
        } else {
            $plant = Plant::where('code', $plantCode)->first();
            if (! $plant) {
                $warnMsg[] = 'Plant not found';
            } else {
                $plantId = $plant->id;
            }
        }

        if (Str::length($iCode) > 0 && (Str::length($iCode) < 6 || ! ctype_alnum($iCode))) {
            $warnMsg[] = 'Invalid item code found';
        } else {
            $itemCode = Item::where('code', $iCode)->first();
            if (! $itemCode) {
                $warnMsg[] = 'Item code not found';
            } else {
                if ($plantId) {
                    $itemCode = Item::where('code', $iCode)->where('plant_id', $plantId)->first();
                    if (! $itemCode) {
                        $warnMsg[] = 'Item code not found for the given plant';
                    } else {
                        $itemId = $itemCode->id;
                    }
                }
            }
        }

        $lineExists = Line::where('name', $lineName)->first();
        if (! $lineExists) {
            $warnMsg[] = 'Line name not found';
        } else {
            if ($plantId) {
                $lineAgainstPlant = Line::where('name', $lineName)->where('plant_id', $plantId)->first();
                if (! $lineAgainstPlant) {
                    $warnMsg[] = 'Line name not found for the given plant';
                } else {
                    $lineId = $lineAgainstPlant->id;
                }
            }
        }

        $workCenterExist = Machine::where('work_center', $workCenter)->first();
        if (! $workCenterExist) {
            $warnMsg[] = 'Work Center not found';
        }

        // $workCenterAgainstPlant = Machine::where('work_center', $workCenter)
        //     ->where('plant_id', $plantId)
        //     ->first();

        // if (!$workCenterAgainstPlant) {
        //     $warnMsg[] = 'Work center not found for the given plant';
        // } else {
        //     $MachineId = $workCenterAgainstPlant->id;
        // }

        if ($plantId != null && $lineId != null) {
            $machineAgaPlantLine = Machine::where('plant_id', $plantId)
                ->where('line_id', $lineId)
                ->where('work_center', $workCenter)
                ->first();

            if (! $machineAgaPlantLine) {
                $warnMsg[] = 'Work center not found for the given plant and line';
            } else {
                $machineId = $machineAgaPlantLine->id;
            }
        }

        if (Str::length($coilNo) > 0 && ! is_numeric($coilNo)) {
            $warnMsg[] = 'Coil number should contain only numeric values!';
        }

        if (Str::length($obserVal) > 0 && ! is_numeric($obserVal)) {
            $warnMsg[] = 'Observed value should contain only numeric values!';
        }

        if (Str::length($status) > 0 && ! in_array($status, ['Ok', 'NotOk'], true)) {
            $warnMsg[] = "Status must be either 'Ok' or 'NotOk'!";
        }
        // else {
        //     if (Str::length($status) <= 0 || ! is_numeric($status) || ! preg_match('/^\d+(\.\d+)?$/', $status)
        //     ) {
        //         $status = 'NotOk';
        //     } else {
        //         $specVal = ProductCharacteristicsMaster::where('plant_id', $plantId)->where('item_id', $itemId)->where('line_id', $lineId)->where('machine_id', $machineId)->first();
        //         if (! $specVal) {
        //             $status = 'NotOk';
        //         }

        //         $lowLimit = $specVal?->lower ?? 0;
        //         $uppLimit = $specVal?->upper ?? 0;

        //         if (Str::length($lowLimit) <= 0 || ! is_numeric($lowLimit) || ! preg_match('/^\d+(\.\d+)?$/', $lowLimit)
        //         ) {
        //             $status = 'NotOk';
        //         } elseif (Str::length($uppLimit) <= 0 || ! is_numeric($uppLimit) || ! preg_match('/^\d+(\.\d+)?$/', $uppLimit)
        //         ) {
        //             $status = 'NotOk';
        //         }

        //         if (($lowLimit == 0 && $uppLimit == 0) || ($uppLimit == 0)) {
        //             $status = 'NotOk';
        //         }

        //         if ($lowLimit > $obserVal || $uppLimit < $obserVal) {
        //             $status = 'NotOk';
        //         }
        //         $status = 'Ok';
        //     }
        // }

        if ($createdBy == null || $createdBy == '' || ! $createdBy) {
            $warnMsg[] = 'Created By cannot be empty';
        }

        if ($plantId) {
            $user = User::where('name', $createdBy)->first();

            $userPlant = User::where('name', $createdBy)->where('plant_id', $plantId)->first();

            if (! $user) {
                $warnMsg[] = 'Created By user name not found!';
            } elseif (! $userPlant && ! $user->hasRole('Super Admin')) {
                $warnMsg[] = "Created By user '{$createdBy}' not found for Plant '{$plantCode}'!";
            } elseif (! $user->hasRole(['Super Admin', 'Process Quality Manager', 'Process Manager', 'Process Supervisor', 'Process Employee'])) {
                $warnMsg[] = 'Created By user does not have rights!';
            }
        }

        if ($plantId && $processOrder) {
            $existing = CharacteristicValue::where('plant_id', $plantId)
                ->where('process_order', $processOrder)
                ->where('coil_number', $coilNo)
                ->first();

            if ($existing) {
                $warnMsg[] = "Coil number '{$coilNo}' already exists for Plant '{$plantCode}' and Process Order '{$processOrder}'.";
            }
        }

        if ($plant && $itemCode && $processOrder != '' && $processOrder != null) {

            $existingOrder = ProcessOrder::where('plant_id', $plantId)
                ->where('process_order', $processOrder)
                ->first();

            if ($existingOrder && $existingOrder->item_id !== ($itemId ?? null)) {
                $warnMsg[] = 'Same Process Order already exists for this Plant with a different Item Code';
            }
        }

        $updatedBy = Filament::auth()->user()->name; // ?? 'Admin'
        if (! $updatedBy) {
            $warnMsg[] = 'Invalid updated by user name found';
        }

        $fromDate = $this->data['created_at'];
        $toDate = $this->data['updated_at'];

        $formats = ['d-m-Y H:i', 'd-m-Y H:i:s']; // '07-05-2025 08:00' or '07-05-2025 08:00:00'

        $fdateTime = null;
        $tdateTime = null;
        // Try parsing with multiple formats
        foreach ($formats as $format) {
            try {
                $fdateTime = Carbon::createFromFormat($format, $fromDate);
                break;
            } catch (\Exception $e) {
                // $warnMsg[] = "Date format mismatch with format: $format";
            }
        }

        foreach ($formats as $format) {
            try {
                $tdateTime = Carbon::createFromFormat($format, $toDate);
                break;
            } catch (\Exception $e) {
                // $warnMsg[] = "Date format mismatch with format: $format";
            }
        }

        if (! isset($fdateTime)) {
            $warnMsg[] = "Invalid 'Created DateTime' format. Expected DD-MM-YYYY HH:MM:SS";
        }
        if (! isset($tdateTime)) {
            $warnMsg[] = "Invalid 'Updated DateTime' format. Expected DD-MM-YYYY HH:MM:SS";
        }

        if (isset($fdateTime) && isset($tdateTime)) {
            if ($fdateTime->greaterThan($tdateTime)) {
                $warnMsg[] = "'Created DataTime' is greater than 'Updated DateTime'.";
            }
        }

        if (! empty($warnMsg)) {
            throw new RowImportFailedException(implode(', ', $warnMsg));
        }

        return CharacteristicValue::updateOrCreate([
            'plant_id' => $plantId,
            'process_order' => $processOrder,
            'coil_number' => $coilNo,
        ],
            [
                'item_id' => $itemId,
                'line_id' => $lineId,
                'machine_id' => $machineId,
                'status' => $status,
                'observed_value' => $obserVal,
                'created_by' => $createdBy,
                'updated_by' => $updatedBy,
                'created_at' => $fdateTime->format('Y-m-d H:i:s'),
                'updated_at' => $tdateTime->format('Y-m-d H:i:s'),
            ]);

        // return null;

        // return new CharacteristicValue;
    }

    public static function getCompletedNotificationBody(Import $import): string
    {
        $body = 'Your characteristic value import has completed and '.number_format($import->successful_rows).' '.str('row')->plural($import->successful_rows).' imported.';

        if ($failedRowsCount = $import->getFailedRowsCount()) {
            $body .= ' '.number_format($failedRowsCount).' '.str('row')->plural($failedRowsCount).' failed to import.';
        }

        return $body;
    }
}
