<?php

namespace App\Filament\Resources;

use App\Filament\Exports\ShiftExporter;
use App\Filament\Imports\ShiftImporter;
use App\Filament\Resources\ShiftResource\Pages;
use App\Models\Plant;
use App\Models\Shift;
use Carbon\Carbon;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ImportAction;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Filament\Forms\Components\Section;
use Filament\Tables\Actions\ExportAction;
use Illuminate\Validation\Rule;

class ShiftResource extends Resource
{
    protected static ?string $model = Shift::class;

    protected static ?string $navigationIcon = 'heroicon-o-rectangle-stack';

    protected static ?string $navigationGroup = 'Master Entries';

    protected static ?int $navigationSort = 4;

    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                Section::make('')
                    ->schema([
                        Forms\Components\Select::make('plant_id')
                        ->relationship('plant', 'name')
                        ->required()
                        // ->nullable()
                        ->reactive()
                        ->options(function (callable $get) {
                            $userHas = Filament::auth()->user()->plant_id;
                            return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::pluck('name', 'id')->toArray();
                        })
                        ->default(function () {
                            return optional(Shift::latest()->first())->plant_id;
                        })
                        ->disabled(fn (Get $get) => !empty($get('id')))
                        // ->afterStateUpdated(fn ($set) => $set('block_id', null) & $set('name', null) & $set('start_time', null) & $set('duration', null) & $set('end_time', null))
                        ->afterStateUpdated(function ($state, callable $set, callable $get) {
                            $plantId = $get('plant_id');
                            $set('block_id', null);
                            if (!$plantId) {
                                $set('sPlantError', 'Please select a plant first.');
                                return;
                            }
                            else
                            {
                                $set('sPlantError', null);
                            }
                        })
                        ->extraAttributes(fn ($get) => [
                            'class' => $get('sPlantError') ? 'border-red-500' : '',
                        ])
                        ->hint(fn ($get) => $get('sPlantError') ? $get('sPlantError') : null)
                        ->hintColor('danger'),
                    Forms\Components\Select::make('block_id')
                        ->relationship('block', 'name')
                        ->required()
                        // ->nullable()
                        ->reactive()
                        ->default(function () {
                            return optional(Shift::latest()->first())->block_id;
                        })
                        // ->disabled(fn (Get $get) => !empty($get('id')))
                        // ->options(fn (callable $get) =>
                        // \App\Models\Block::where('plant_id', $get('plant_id'))
                        //     ->pluck('name', 'id')
                        //     ->toArray() // Convert collection to array
                        // )
                        ->options(function (callable $get) {
                            if (!$get('plant_id')) {
                                return [];
                            }

                            return \App\Models\Block::where('plant_id', $get('plant_id'))
                                ->pluck('name', 'id')
                                ->toArray();
                        })
                        // ->afterStateUpdated(fn ($set) => $set('name', null))
                        ->afterStateUpdated(function ($state, callable $set, callable $get) {
                            $blockId = $get('block_id');
                            $set('name', null);
                            if (!$blockId) {
                                $set('sBlockError', 'Please select a block first.');
                                return;
                            }
                            else
                            {
                                $set('sBlockError', null);
                            }
                        })
                        ->extraAttributes(fn ($get) => [
                            'class' => $get('sBlockError') ? 'border-red-500' : '',
                        ])
                        ->hint(fn ($get) => $get('sBlockError') ? $get('sBlockError') : null)
                        ->hintColor('danger'),
                    Forms\Components\TextInput::make('name')
                        ->placeholder('Scan the valid name')
                        ->autofocus(true)
                        ->required()
                        ->reactive()
                        ->afterStateUpdated(function ($state, callable $set, callable $get) {
                            $nameId = $get('name');
                            $set('start_time', null);
                            if (!$nameId) {
                                $set('sNameError', 'Scan the valid name.');
                                return;
                            }
                            else
                            {
                                // $exists = Shift::where('plant_id', $get('plant_id'))
                                //     ->where('block_id', $get('block_id'))
                                //     ->where('name', $nameId)
                                //     ->latest()
                                //     ->exists();
                                // if ($exists)
                                // {
                                //     $set('start_time', null);
                                //     $set('sNameError', 'Scanned name already exist.');
                                //     return;
                                // }
                                $set('sNameError', null);
                            }
                        })
                        ->extraAttributes(fn ($get) => [
                            'class' => $get('sNameError') ? 'border-red-500' : '',
                        ])
                        ->hint(fn ($get) => $get('sNameError') ? $get('sNameError') : null)
                        ->hintColor('danger')
                        ->rule(function (callable $get) {
                            return Rule::unique('shifts', 'name')
                                ->where('plant_id', $get('plant_id'))
                                ->where('block_id', $get('block_id'))
                                ->ignore($get('id')); // Ignore current record during updates
                        }),
                    Forms\Components\TimePicker::make('start_time')
                        ->required()
                        ->label('Start Time')
                        ->live()
                        // ->afterStateUpdated(fn (callable $set, callable $get, $state) =>
                        // $set('end_time', self::calculateEndTime($state, $get('duration')))
                        // )
                        ->reactive()
                        ->afterStateUpdated(function ($state, callable $set, callable $get) {
                            $startTime = $get('start_time');
                            $set('duration', null);
                            $set('end_time', self::calculateEndTime($state, $get('duration')));
                            if (!$startTime) {
                                $set('sStartTimeError', 'Choose the valid start time.');
                                return;
                            }
                            else
                            {
                                // $exists = Shift::where('plant_id', $get('plant_id'))
                                //     ->where('block_id', $get('block_id'))
                                //     ->where('name', $get('name'))
                                //     ->latest()
                                //     ->exists();
                                // if ($exists)
                                // {
                                //     $set('start_time', null);
                                //     $set('sStartTimeError', null);
                                //     $set('sNameError', 'Scanned name already exist.');
                                //     return;
                                // }
                                $set('sStartTimeError', null);
                            }
                        })
                        ->extraAttributes(fn ($get) => [
                            'class' => $get('sStartTimeError') ? 'border-red-500' : '',
                        ])
                        ->hint(fn ($get) => $get('sStartTimeError') ? $get('sStartTimeError') : null)
                        ->hintColor('danger'),
                    Forms\Components\TextInput::make('duration')
                        ->required()
                        ->placeholder('Scan the valid duration')
                        ->numeric()
                        ->inputMode('decimal')
                        ->minValue(0.01) // Minimum valid duration
                        ->lazy()
                        // ->afterStateUpdated(fn (callable $set, callable $get, $state) =>
                        // $set('end_time', self::calculateEndTime($get('start_time'), $state))
                        // )
                        ->reactive()
                        ->afterStateUpdated(function ($state, callable $set, callable $get) {
                            $duration = $get('duration');
                            // $set('end_time', null);
                            $set('end_time', self::calculateEndTime($get('start_time'), $state));
                            if (!$duration) {
                                $set('sDurationError', 'Scan the valid duration.');
                                return;
                            }
                            else
                            {
                                [$hRs, $miNs] = explode('.', $duration) + [0, 0]; // Ensure two parts
                                $hRs = (int) $hRs;
                                $miNs = (int) $miNs;

                                $set('duration', $hRs.'.'.$miNs);

                                if ($miNs > 60) {
                                    $set('sDurationError', 'Minutes exceeds 1 hour.');
                                    $set('duration', null);
                                    $set('end_time', null);
                                    return;
                                }

                                $totalMinutes = $hRs * 60 + $miNs;

                                if ($totalMinutes > 1440) {
                                    $set('sDurationError', 'Duration exceeds 24 hours.');
                                    $set('duration', null);
                                    $set('end_time', null);
                                    return;
                                }
                                $set('sDurationError', null);
                            }
                        })
                        ->extraAttributes(fn ($get) => [
                            'class' => $get('sDurationError') ? 'border-red-500' : '',
                        ])
                        ->hint(fn ($get) => $get('sDurationError') ? $get('sDurationError') : null)
                        ->hintColor('danger'),
                    Forms\Components\TimePicker::make('end_time')
                        ->required()
                        ->label('End Time')
                        ->readOnly()
                        // ->native(false),
                        ->reactive()
                        ->afterStateUpdated(function ($state, callable $set, callable $get) {
                            $endTime = $get('end_time');
                            $set('end_time', self::calculateEndTime($get('start_time'), $state));
                            if (!$endTime) {
                                $set('sEndTimeError', 'Choose the valid start time & duration.');
                                return;
                            }
                            else
                            {
                                $set('sEndTimeError', null);
                            }
                        })
                        ->extraAttributes(fn ($get) => [
                            'class' => $get('sEndTimeError') ? 'border-red-500' : '',
                        ])
                        ->hint(fn ($get) => $get('sEndTimeError') ? $get('sEndTimeError') : null)
                        ->hintColor('danger'),
                    Forms\Components\TextInput::make('id')
                        ->hidden()
                        ->readOnly(),
                ])
                ->columns(2),
            ]);
    }

    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                // Tables\Columns\TextColumn::make('id')
                //     ->label('ID')
                //     ->numeric()
                //     ->sortable(),
                Tables\Columns\TextColumn::make('No.')
                    ->label('No.')
                    ->getStateUsing(function ($record, $livewire, $column, $rowLoop) {
                        $paginator = $livewire->getTableRecords();
                        $perPage = method_exists($paginator, 'perPage') ? $paginator->perPage() : 10;
                        $currentPage = method_exists($paginator, 'currentPage') ? $paginator->currentPage() : 1;
                        return ($currentPage - 1) * $perPage + $rowLoop->iteration;
                    }),
                Tables\Columns\TextColumn::make('name')
                    ->label('Shift')
                    ->alignCenter()
                    ->sortable()
                    ->searchable(),
                Tables\Columns\TextColumn::make('start_time')
                    ->label('Start Time')
                    ->alignCenter()
                    ->sortable(),
                Tables\Columns\TextColumn::make('duration')
                    ->label('Duration')
                    ->alignCenter()
                    ->sortable(),
                Tables\Columns\TextColumn::make('end_time')
                    ->label('End Time')
                    ->alignCenter(),
                Tables\Columns\TextColumn::make('block.name')
                    ->label('Block')
                    ->alignCenter()
                    ->sortable()
                    ->searchable(),
                Tables\Columns\TextColumn::make('plant.name')
                    ->label('Plant')
                    ->alignCenter()
                    ->sortable()
                    ->searchable(),
                Tables\Columns\TextColumn::make('created_at')
                    ->label('Created At')
                    ->dateTime()
                    ->alignCenter()
                    ->sortable(),
                Tables\Columns\TextColumn::make('updated_at')
                    ->label('Updated At')
                    ->dateTime()
                    ->alignCenter()
                    ->sortable()
                    ->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('deleted_at')
                    ->label('Deleted At')
                    ->dateTime()
                    ->alignCenter()
                    ->sortable()
                    ->toggleable(isToggledHiddenByDefault: true),
            ])
            ->filters([
                Tables\Filters\TrashedFilter::make(),
            ])
            ->actions([
                Tables\Actions\ViewAction::make(),
                Tables\Actions\EditAction::make(),
            ])
            ->bulkActions([
                Tables\Actions\BulkActionGroup::make([
                    Tables\Actions\DeleteBulkAction::make(),
                    Tables\Actions\ForceDeleteBulkAction::make(),
                    Tables\Actions\RestoreBulkAction::make(),
                ]),
            ])
            ->headerActions([
                ImportAction::make()
                    ->label('Import Shifts')
                    ->color('warning')
                    ->importer(ShiftImporter::class)
                    ->visible(function() {
                        return Filament::auth()->user()->can('view import shift');
                    }),
                ExportAction::make()
                    ->label('Export Shifts')
                    ->color('warning')
                    ->exporter(ShiftExporter::class)
                    ->visible(function() {
                        return Filament::auth()->user()->can('view export shift');
                    }),
            ]);
    }

    public static function getRelations(): array
    {
        return [
            //
        ];
    }

    public static function getPages(): array
    {
        return [
            'index' => Pages\ListShifts::route('/'),
            'create' => Pages\CreateShift::route('/create'),
            'view' => Pages\ViewShift::route('/{record}'),
            'edit' => Pages\EditShift::route('/{record}/edit'),
        ];
    }

    public static function getEloquentQuery(): Builder
    {
        return parent::getEloquentQuery()
            ->withoutGlobalScopes([
                SoftDeletingScope::class,
            ]);
    }

    protected static function calculateEndTime(?string $startTime, ?string $duration): ?string
    {
        if (!$startTime || !$duration) {
            return null;
        }

        try {
            // Convert start_time to Carbon instance
            $startTimeCarbon = Carbon::createFromFormat('H:i:s', $startTime);

            // Ensure duration is in a valid numeric format
            $duration = str_replace(',', '.', $duration); // Handle decimal formats
            if (!is_numeric($duration)) {
                return null; // Invalid duration format
            }

            // Extract hours and minutes correctly
            [$hours, $decimalMinutes] = explode('.', $duration) + [0, 0]; // Ensure two parts
            $hours = (int) $hours; // Convert to integer hours
            $minutes = (int) $decimalMinutes; // Directly use decimal part as minutes

            // Calculate end time
            $endTimeCarbon = $startTimeCarbon->addHours($hours)->addMinutes($minutes);

            return $endTimeCarbon->format('H:i:s'); // Return formatted end time
        } catch (\Exception $e) {
            return null;
        }
    }
}
