<?php

namespace App\Filament\Imports;

use App\Models\Block;
use App\Models\Item;
use App\Models\Line;
use App\Models\Plant;
use App\Models\ProductionQuantity;
use App\Models\Shift;
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 Illuminate\Database\Eloquent\Model;
use Str;

class ProductionQuantityImporter extends Importer
{
    protected static ?string $model = ProductionQuantity::class;

    public static function getColumns(): array
    {
        return [
            ImportColumn::make('created_at')
                ->requiredMapping()
                ->exampleHeader('Created DateTime')
                ->example(['01-01-2025 08:00:00', '01-01-2025 19:30:00'])
                ->label('Created DateTime')
                ->rules(['required']),
            ImportColumn::make('production_order')
                ->requiredMapping()
                ->exampleHeader('Production Order')
                ->example(['1234567', '1234567'])
                ->label('Production Order')
                ->numeric(),
            ImportColumn::make('item')
                ->requiredMapping()
                ->exampleHeader('Item Code')
                ->example(['123456', '123456'])
                ->label('Item Code')
                ->relationship(resolveUsing: 'code')
                ->rules(['required']),
            ImportColumn::make('serial_number')
                ->requiredMapping()
                ->exampleHeader('Serial Number')
                ->example(['12345678901234', '12345678902234'])
                ->label('Serial Number')
                ->rules(['required']),
            ImportColumn::make('line')
                ->requiredMapping()
                ->exampleHeader('Line Name')
                ->example(['4 inch pump line', '4 inch pump line'])
                ->label('Line Name')
                ->relationship(resolveUsing: 'name')
                ->rules(['required']),
            ImportColumn::make('block_reference')
                ->requiredMapping() // Or optionalMapping() if not always present
                ->exampleHeader('Block Name')
                ->example(['Block A', 'Block A'])
                ->label('Block Name')
                ->rules(['required']), // Or remove if not required
            ImportColumn::make('shift')
                ->requiredMapping()
                ->exampleHeader('Shift Name')
                ->example(['Day', 'Night'])
                ->label('Shift Name')
                ->relationship(resolveUsing: 'name')
                ->rules(['required']),
            ImportColumn::make('plant')
                ->requiredMapping()
                ->exampleHeader('Plant Code')
                ->example(['1000', '1000'])
                ->label('Plant Code')
                ->relationship(resolveUsing: 'code')
                ->rules(['required']),
            ImportColumn::make('updated_at')
                ->requiredMapping()
                ->exampleHeader('Updated DateTime')
                ->example(['01-01-2025 08:00:00', '01-01-2025 19:30:00'])
                ->label('Updated DateTime')
                ->rules(['required']),
            ImportColumn::make('operator_id')
                ->requiredMapping()
                ->exampleHeader('Operator ID')
                ->example([Filament::auth()->user()->name, Filament::auth()->user()->name])
                ->label('Operator ID')
                ->rules(['required']),
        ];
    }

    public function resolveRecord(): ?ProductionQuantity
    {
        $warnMsg = [];
        $plantCod = $this->data['plant'];
        $plant = null;
        $line = null;
        $block = null;
        $shift = null;
        if (Str::length($plantCod) < 4 || ! is_numeric($plantCod) || ! preg_match('/^[1-9]\d{3,}$/', $plantCod)) {
            $warnMsg[] = 'Invalid plant code found';
        } else {
            $plant = Plant::where('code', $plantCod)->first();
        }

        if (! $plant) {
            $warnMsg[] = 'Plant not found';
        } else {
            $line = Line::where('name', $this->data['line'])->where('plant_id', $plant->id)->first();
            // block_reference
            $block = Block::where('name', $this->data['block_reference'])->where('plant_id', $plant->id)->first();
        }

        if (! $line) {
            $warnMsg[] = 'Line not found';
        }
        if (! $block) {
            $warnMsg[] = 'Block not found';
        } elseif ($plant) {
            $shift = Shift::where('name', $this->data['shift'])->where('plant_id', $plant->id)->where('block_id', $block->id)->first();
        }

        // $shift = Shift::where('id', $this->data['shift'])->where('plant_id', $plant->id)->first();
        if (! $shift) {
            $warnMsg[] = 'Shift not found';
        }

        $item = null;
        if ($plant) {
            $item = Item::where('code', $this->data['item'])->where('plant_id', $plant->id)->first();
        }
        if (! $item) {
            $warnMsg[] = 'Item not found';
        }
        if (Str::length($this->data['serial_number']) < 9 || ! ctype_alnum($this->data['serial_number'])) {
            $warnMsg[] = 'Invalid serial number found';
        }
        if (Str::length($this->data['production_order']) > 0 && (Str::length($this->data['production_order']) < 7 || Str::length($this->data['production_order']) > 14 || ! is_numeric($this->data['production_order']))) {
            $warnMsg[] = 'Invalid production order 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) {
                // Optionally collect warning messages
                // $warnMsg[] = "Date format mismatch with format: $format";
            }
        }

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

        // $fDateOnly = '';
        if (! isset($fdateTime)) {
            // throw new \Exception('Invalid date time format');
            $warnMsg[] = "Invalid 'Created DateTime' format. Expected DD-MM-YYYY HH:MM:SS";
        }
        // else {
        //     $fDateOnly = $fdateTime->toDateString();
        // }
        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 (!$fromDate) {
        //     $warnMsg[] = "Invalid 'Created DateTime' format. Expected DD-MM-YYYY HH:MM:SS";
        // }
        // else if (!$toDate) {
        //     $warnMsg[] = "Invalid 'Updated DateTime' format. Expected DD-MM-YYYY HH:MM:SS";
        // }

        $user = User::where('name', $this->data['operator_id'])->first();
        if (! $user) {
            $warnMsg[] = 'Operator ID not found';
        }

        if (! empty($warnMsg)) {
            throw new RowImportFailedException(implode(', ', $warnMsg));
        } else { // if (empty($warnMsg))
            $productionQuan = ProductionQuantity::where('plant_id', $plant->id)
                ->where('serial_number', $this->data['serial_number'])
                ->latest()
                ->first();

            if ($productionQuan) {
                throw new RowImportFailedException('Serial number already exist!');
            }
        }

        ProductionQuantity::updateOrCreate([
            'serial_number' => $this->data['serial_number'],
            'plant_id' => $plant->id,
            'shift_id' => $shift->id,
            'line_id' => $line->id,
            'item_id' => $item->id,
            'production_order' => $this->data['production_order'] ?? null,
            'created_at' => $fdateTime->format('Y-m-d H:i:s'), // $this->data['created_at'],
            'updated_at' => $tdateTime->format('Y-m-d H:i:s'), // $this->data['updated_at'],
            'operator_id' => $this->data['operator_id'],
        ]);

        // ProductionQuantity::updateOrCreate([
        //             'serial_number' => $this->data['serial_number'],
        //             'plant_id' => $plant->id,
        //         ],
        //         [
        //         'shift_id' => $shift->id,
        //         'line_id' => $line->id,
        //         'item_id' => $item->id,
        //         'production_order' => $this->data['production_order'] ?? null,
        //         'created_at' => $fdateTime->format('Y-m-d H:i:s'),//$this->data['created_at'],
        //         'updated_at' => $tdateTime->format('Y-m-d H:i:s'),//$this->data['updated_at'],
        //         'operator_id' => $this->data['operator_id'],
        // ]);
        return null;

        // return new ProductionQuantity();
    }

    public static function getCompletedNotificationBody(Import $import): string
    {
        $body = 'Your production quantity 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;
    }

    public function processRow(array $row): Model
    {
        // Activate import flag
        ProductionQuantity::$importing = true;

        try {
            // Create record with relationships
            $productionQuantity = ProductionQuantity::create([
                'created_at' => $row['created_at'],
                'item_id' => $this->resolveItemId($row['item']),
                'serial_number' => $row['serial_number'],
                'line_id' => $this->resolveLineId($row['line']),
                'shift_id' => $this->resolveShiftId($row['shift']),
                'plant_id' => $this->resolvePlantId($row['plant']),
                'updated_at' => $row['updated_at'],
            ]);
        } finally {
            // Always disable flag even if errors occur
            ProductionQuantity::$importing = false;
        }

        return $productionQuantity;
    }

    // Relationship resolvers
    private function resolveItemId(string $code): int
    {
        return Item::where('code', $code)->first()->id;
    }

    private function resolveLineId(string $name): int
    {
        return Line::where('name', $name)->first()->id;
    }

    private function resolveShiftId(string $name): int
    {
        return Shift::where('name', $name)->first()->id;
    }

    private function resolvePlantId(string $name): int
    {
        return Plant::where('name', $name)->first()->id;
    }
}
