<?php

namespace App\Filament\Resources;

use App\Filament\Exports\InvoiceDataValidationExporter;
use App\Filament\Resources\InvoiceDataValidationResource\Pages;
use App\Models\InvoiceDataValidation;
use App\Models\Plant;
use DB;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Form;
use Filament\Forms\Get;
use Filament\Notifications\Notification;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Actions\ExportAction;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
use Illuminate\Support\Facades\Storage;
use Maatwebsite\Excel\Facades\Excel;

class InvoiceDataValidationResource extends Resource
{
    protected static ?string $model = InvoiceDataValidation::class;

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

    protected static ?string $navigationGroup = 'Manufacturing SD';

    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                Forms\Components\Select::make('plant_id')
                    ->label('Plant')
                    ->relationship('plant', 'name')
                    ->options(function (callable $get) {
                        $userHas = Filament::auth()->user()->plant_id;

                        return ($userHas && strlen($userHas) > 0) ? Plant::where('id', $userHas)->pluck('name', 'id')->toArray() : Plant::orderBy('code')->pluck('name', 'id')->toArray();
                    })
                    ->required(),
                Forms\Components\TextInput::make('distribution_channel_desc')
                    ->label('Distribution Channel Description')
                    ->required(),
                Forms\Components\TextInput::make('customer_code')
                    ->label('Customer Code')
                    ->required(),
                Forms\Components\TextInput::make('document_number')
                    ->label('Document Number')
                    ->required(),
                Forms\Components\DatePicker::make('document_date')
                    ->label('Document Date')
                    ->required(),
                Forms\Components\TextInput::make('customer_trade_name')
                    ->label('Customer Trade Name')
                    ->required(),
                Forms\Components\TextInput::make('customer_location')
                    ->label('Customer Location')
                    ->required(),
                Forms\Components\TextInput::make('location')
                    ->label('Location')
                    ->required(),
                Forms\Components\TextInput::make('remark')
                    ->label('Remark'),
                Forms\Components\Hidden::make('created_by')
                    ->label('Created By')
                    ->default(Filament::auth()->user()?->name),
                Forms\Components\Hidden::make('updated_by')
                    ->label('Updated By')
                    ->default(Filament::auth()->user()?->name),
            ]);
    }

    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                Tables\Columns\TextColumn::make('No.')
                    ->label('No.')
                    ->alignCenter()
                    ->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('plant.code')
                    ->label('Plant')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('distribution_channel_desc')
                    ->label('Distribution Channel Description')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('customer_code')
                    ->label('Customer Code')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('document_number')
                    ->label('Document Number')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('document_date')
                    ->label('Document Date')
                    ->alignCenter()
                    ->searchable()
                    ->date()
                    ->sortable(),
                Tables\Columns\TextColumn::make('customer_trade_name')
                    ->label('Customer Trade Name')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('customer_location')
                    ->label('Customer Location')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('location')
                    ->label('Location')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('remark')
                    ->label('Remark')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('created_at')
                    ->label('Created At')
                    ->alignCenter()
                    ->searchable()
                    ->dateTime()
                    ->sortable(),
                // ->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('created_by')
                    ->label('Created By')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('updated_at')
                    ->label('Updated At')
                    ->alignCenter()
                    ->searchable()
                    ->dateTime()
                    ->sortable()
                    ->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('updated_by')
                    ->label('Updated By')
                    ->alignCenter()
                    ->searchable()
                    ->sortable()
                    ->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('deleted_at')
                    ->label('Deleted At')
                    ->alignCenter()
                    ->dateTime()
                    ->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([
                Tables\Actions\Action::make('Import Invoice Data')
                    ->label('Import Invoice Data')
                    ->form([
                        FileUpload::make('invoice_data_file')
                            ->label('Invoice Data File')
                            // ->required()
                            ->preserveFilenames()
                            ->storeFiles(false)
                            ->reactive()
                            ->required()
                            ->disk('local')
                            // ->visible(fn (Get $get) => !empty($get('plant_id')))
                            ->directory('uploads/temp'),
                    ])
                    ->action(function (array $data) {
                        $uploadedFile = $data['invoice_data_file'];

                        $disk = Storage::disk('local');

                        $user = Filament::auth()->user();

                        $operatorName = $user->name;

                        // Get original filename
                        $originalName = $uploadedFile->getClientOriginalName(); // e.g. 3RA0018732.xlsx

                        $originalNameOnly = pathinfo($originalName, PATHINFO_FILENAME);

                        // Store manually using storeAs to keep original name
                        $path = $uploadedFile->storeAs('uploads/InvoiceOut', $originalName, 'local'); // returns relative path

                        $fullPath = Storage::disk('local')->path($path);

                        if ($fullPath && file_exists($fullPath)) {
                            $rows = Excel::toArray(null, $fullPath)[0];

                            if ((count($rows) - 1) <= 0) {
                                Notification::make()
                                    ->title('Records Not Found')
                                    ->body("Import the valid 'Invoice Data' file to proceed..!")
                                    ->danger()
                                    ->send();

                                if ($disk->exists($path)) {
                                    $disk->delete($path);
                                }

                                return;
                            }

                            $invalidPlantCode = [];
                            $invalidPlaCoFound = [];
                            $invalidDisChaDesc = [];
                            $invalidCustomerCode = [];
                            $invalidDocNo = [];
                            $invalidDocDate = [];
                            $invalidCusTradeName = [];
                            $invalidCusLocation = [];
                            $invalidUser = [];
                            $userNotFound = [];
                            $invalidPlantType = [];
                            $invalidLocation = [];

                            $seenPlantDoc = [];
                            // $duplicateEntries = [];
                            $duplicateEntriesExcel = [];

                            foreach ($rows as $index => $row) {
                                if ($index == 0) {
                                    continue;
                                }  // Skip header

                                $DisChaDesc = trim($row[3]);
                                $plantCode = trim($row[4]);
                                $CustomerCode = trim($row[5]);
                                $DocNo = trim($row[6]);
                                $DocDate = trim($row[7]);
                                $CusTradeName = trim($row[9]);
                                $CusLocation = trim($row[10]);
                                $Location = trim($row[36]);

                                // if (empty($plantCode))    $invalidPlantCode[] = "Row {$index}";
                                if (empty($DisChaDesc)) {
                                    $invalidDisChaDesc[] = "Row {$index}";
                                }
                                if (empty($CustomerCode)) {
                                    $invalidCustomerCode[] = "Row {$index}";
                                }
                                if (empty($DocNo)) {
                                    $invalidDocNo[] = "Row {$index}";
                                }
                                if (empty($CusTradeName)) {
                                    $invalidCusTradeName[] = "Row {$index}";
                                }
                                if (empty($CusLocation)) {
                                    $invalidCusLocation[] = "Row {$index}";
                                }
                                if (empty($Location)) {
                                    $invalidLocation[] = "Row {$index}";
                                }
                                // if (empty($createdBy))    $invalidUser[] = "Row {$index}";

                                if (strlen($plantCode) < 4) {
                                    $invalidPlantCode[] = $plantCode;
                                }
                                if (! is_numeric($plantCode)) {
                                    $invalidPlantType[] = $plantCode;
                                } elseif (! Plant::where('code', $plantCode)->first()) {
                                    $invalidPlaCoFound[] = $plantCode;
                                }

                                // --- Find Plant by code ---
                                $plant = Plant::where('code', $plantCode)->first();

                                // //Duplicate Check in DB ---
                                // $exists = InvoiceDataValidation::where('plant_id', $plant->id)
                                //     ->where('document_number', $DocNo)
                                //     ->first();

                                // if ($exists)
                                // {
                                //     $duplicateEntries[] = "Duplicate record: Document Number '{$DocNo}' already exists for Plant '{$plant->name}'";
                                // }

                                // Also check duplicates within the same file ---
                                $uniqueKey = $plantCode.'_'.$DocNo;
                                if (in_array($uniqueKey, $seenPlantDoc)) {
                                    $duplicateEntriesExcel[] = "Duplicate in file at Row {$index}: Document Number '{$DocNo}' already exists for Plant '{$plant->name}'";
                                }
                                $seenPlantDoc[] = $uniqueKey;
                            }

                            if (! empty($invalidCustomerCode) || ! empty($invalidDocNo) || ! empty($invalidDocDate) || ! empty($invalidCusTradeName) || ! empty($invalidCusLocation)) {
                                $errorMsg = '';

                                // if (!empty($invalidDisChaDesc))   $errorMsg .= 'Missing Distribution Channel Description in rows: ' . implode(', ', $invalidDisChaDesc) . '<br>';
                                if (! empty($invalidCustomerCode)) {
                                    $errorMsg .= 'Missing Customer Code in rows: '.implode(', ', $invalidCustomerCode).'<br>';
                                }
                                if (! empty($invalidDocNo)) {
                                    $errorMsg .= 'Missing Document Number in rows: '.implode(', ', $invalidDocNo).'<br>';
                                }
                                if (! empty($invalidDocDate)) {
                                    $errorMsg .= 'Missing Document Date in rows: '.implode(', ', $invalidDocDate).'<br>';
                                }
                                if (! empty($invalidCusTradeName)) {
                                    $errorMsg .= 'Missing Customer Trade Name in rows: '.implode(', ', $invalidCusTradeName).'<br>';
                                }
                                if (! empty($invalidCusLocation)) {
                                    $errorMsg .= 'Missing Customer Location in rows: '.implode(', ', $invalidCusLocation).'<br>';
                                }
                                if (! empty($invalidLocation)) {
                                    $errorMsg .= 'Missing Location in rows: '.implode(', ', $invalidLocation).'<br>';
                                }

                                Notification::make()
                                    ->title('Missing Mandatory Fields')
                                    ->body($errorMsg)
                                    ->danger()
                                    ->send();

                                if ($disk->exists($path)) {
                                    $disk->delete($path);
                                }

                                return;
                            } elseif (! empty($invalidPlantCode)) {
                                $invalidPlantCode = array_unique($invalidPlantCode);
                                Notification::make()
                                    ->title('Invalid Plant Codes')
                                    ->body('The following plant codes should contain minimum 4 digits:<br>'.implode(', ', $invalidPlantCode))
                                    ->danger()
                                    ->send();
                                if ($disk->exists($path)) {
                                    $disk->delete($path);
                                }

                                return;
                            } elseif (! empty($invalidPlantType)) {
                                $invalidPlantType = array_unique($invalidPlantType);
                                Notification::make()
                                    ->title('Invalid Plant Codes')
                                    ->body('The following plant codes should contain numeric values:<br>'.implode(', ', $invalidPlantType))
                                    ->danger()
                                    ->send();
                                if ($disk->exists($path)) {
                                    $disk->delete($path);
                                }

                                return;
                            } elseif (! empty($invalidPlaCoFound)) {
                                $invalidPlaCoFound = array_unique($invalidPlaCoFound);
                                Notification::make()
                                    ->title('Invalid Plant Codes')
                                    ->body('The following plant codes not found in plants:<br>'.implode(', ', $invalidPlaCoFound))
                                    ->danger()
                                    ->send();
                                if ($disk->exists($path)) {
                                    $disk->delete($path);
                                }

                                return;
                            }

                            // if (!empty($duplicateEntries))
                            // {
                            //     $duplicateGroupedByPlant = [];

                            //     foreach ($duplicateEntries as $message)
                            //     {
                            //         if (preg_match("/Document Number '([^']+)' already exists for Plant '([^']+)'/", $message, $matches)) {
                            //             $docNo = $matches[1];
                            //             $plantName = trim($matches[2]);
                            //             $duplicateGroupedByPlant[$plantName][] = $docNo;
                            //         }
                            //     }

                            //     $errorMsg = 'Duplicate Document Number found in Database :<br>';

                            //     foreach ($duplicateGroupedByPlant as $plant => $docNumbers) {
                            //         $count = count($docNumbers);

                            //         if ($count > 10)
                            //         {
                            //             $errorMsg .= "Duplicate record(s) for Plant <b>{$plant}</b> : {$count} document numbers already exist in DB<br>";
                            //         }
                            //         else
                            //         {
                            //             $errorMsg .= "Duplicate record(s) for Plant <b>{$plant}</b> : "
                            //                 . implode(', ', $docNumbers)
                            //                 . " already exist<br>";
                            //         }
                            //     }

                            //     Notification::make()
                            //         //->title('Duplicate Entries in Database')
                            //         ->body($errorMsg)
                            //         ->danger()
                            //         ->send();

                            //     if ($disk->exists($path)) {
                            //         $disk->delete($path);
                            //     }
                            //     return;
                            // }

                            if (! empty($duplicateEntriesExcel)) {
                                $duplicateGroupedByPlantExcel = [];

                                foreach ($duplicateEntriesExcel as $message) {// "/Document Number '([^']+)' already exist(?:s)?(?: for Plant (.+))?/"
                                    if (preg_match("/Document Number '([^']+)' already exists for Plant '([^']+)'/", $message, $matches)) {
                                        $docNo = $matches[1];
                                        $plantName = $matches[2] ?? 'Unknown';
                                        $duplicateGroupedByPlantExcel[$plantName][] = $docNo;
                                    }
                                }

                                $errorMsg = 'Duplicate Document Number found in Uploaded File :<br>';

                                foreach ($duplicateGroupedByPlantExcel as $plant => $docNumbers) {
                                    // Remove duplicate document numbers for each plant
                                    $uniqueDocNumbers = array_unique($docNumbers);
                                    $count = count($uniqueDocNumbers);

                                    if ($count > 10) {
                                        $errorMsg .= "Duplicate Document Numbers for Plant <b>{$plant}</b> : {$count} Document Numbers already exist in uploaded file<br>";
                                    } else {
                                        $errorMsg .= "Duplicate Document Numbers for Plant <b>{$plant}</b> : '"
                                            .implode(', ', $uniqueDocNumbers)
                                            ."' already exist in uploaded file<br>";
                                    }
                                }

                                Notification::make()
                                    // ->title('Duplicate Document Number in Uploaded File')
                                    ->body($errorMsg)
                                    ->danger()
                                    ->send();

                                if ($disk->exists($path)) {
                                    $disk->delete($path);
                                }

                                return;
                            }

                            // if (!empty($duplicateEntriesExcel))
                            // {
                            //     //$errorMsg = 'Duplicate Document Number found in the uploaded file:<br>' . implode('<br>', $duplicateEntriesExcel);
                            //     $errorMsg = buildDuplicateMessage($duplicateEntriesExcel, 'Duplicate Document Number found in Uploaded File');
                            //     Notification::make()
                            //         ->title('Duplicate Document Number in Uploaded File')
                            //         ->body($errorMsg)

                            $successCount = 0;
                            $failedRecords = [];

                            DB::beginTransaction();

                            try {
                                foreach ($rows as $index => $row) {
                                    if ($index == 0) {
                                        continue;
                                    }

                                    $rowNumber = $index + 1;

                                    try {
                                        $DisChaDesc = trim($row[3]);
                                        $plantCode = trim($row[4]);
                                        $CustomerCode = trim($row[5]);
                                        $DocNo = trim($row[6]);
                                        $DocDate = trim($row[7]);
                                        $CusTradeName = trim($row[9]);
                                        $CusLocation = trim($row[10]);
                                        $Location = trim($row[36]);

                                        if (empty($DocNo)) {
                                            throw new \Exception("Row '{$rowNumber}' Missing QR Code");
                                        }

                                        $plant = Plant::where('code', $plantCode)->first();
                                        if (! $plant) {
                                            throw new \Exception("Invalid plant code : '{$plantCode}'");
                                        }

                                        if (! empty($DocDate)) {
                                            if (preg_match('/^\d{2}[-\/]\d{2}[-\/]\d{4}$/', $DocDate)) {
                                                [$day, $month, $year] = preg_split('/[-\/]/', $DocDate);
                                                $formattedDate = "{$year}-{$month}-{$day}";
                                            } elseif (is_numeric($DocDate)) {
                                                $formattedDate = \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($DocDate)->format('Y-m-d');
                                            } else {
                                                $formattedDate = date('Y-m-d', strtotime($DocDate));
                                            }
                                        } else {
                                            $formattedDate = null;
                                        }

                                        $record = InvoiceDataValidation::where('plant_id', $plant->id)
                                            ->where('document_number', $DocNo)
                                            ->first();

                                        $curStat = $record ? 'Updation' : 'Insertion';

                                        if ($record) {
                                            $record->update([
                                                'distribution_channel_desc' => $DisChaDesc,
                                                'customer_code' => $CustomerCode,
                                                'document_date' => $formattedDate,
                                                'customer_trade_name' => $CusTradeName,
                                                'customer_location' => $CusLocation,
                                                'location' => $Location,
                                                'updated_by' => $operatorName,
                                            ]);
                                            $inserted = $record;
                                        } else {
                                            // Record does not exist, create with 'created_by'
                                            $inserted = InvoiceDataValidation::create([
                                                'plant_id' => $plant->id,
                                                'document_number' => $DocNo,
                                                'distribution_channel_desc' => $DisChaDesc,
                                                'customer_code' => $CustomerCode,
                                                'document_date' => $formattedDate,
                                                'customer_trade_name' => $CusTradeName,
                                                'customer_location' => $CusLocation,
                                                'location' => $Location,
                                                'created_by' => $operatorName,
                                            ]);
                                        }
                                        // $inserted = InvoiceDataValidation::create([
                                        //     'plant_id'                  => $plant->id,
                                        //     'document_number'           => $DocNo,
                                        //     'distribution_channel_desc' => $DisChaDesc,
                                        //     'customer_code'             => $CustomerCode,
                                        //     'document_date'             => $formattedDate,
                                        //     'customer_trade_name'       => $CusTradeName,
                                        //     'customer_location'         => $CusLocation,
                                        //     'created_by'                => $operatorName
                                        // ]);

                                        if (! $inserted) {
                                            throw new \Exception("{$curStat} failed for Document Number : {$DocNo}");
                                        }

                                        $successCount++;
                                    } catch (\Exception $e) {
                                        $failedRecords[] = [
                                            'row' => $rowNumber,
                                            'document_number' => $DocNo ?? null,
                                            'error' => $e->getMessage(),
                                        ];
                                    }
                                }

                                DB::commit();

                                if (count($failedRecords) > 0) {
                                    $failedSummary = collect($failedRecords)
                                        ->map(fn ($f) => "Row {$f['row']} ({$f['document_number']}) : {$f['error']}")
                                        ->take(5) // limit preview to first 5 errors
                                        ->implode("\n");

                                    Notification::make()
                                        ->title('Partial Import Warning')
                                        ->body("'{$successCount}' records inserted. ".count($failedRecords)." failed.\n\n{$failedSummary}")
                                        ->warning()
                                        ->send();
                                } else {
                                    Notification::make()
                                        ->title('Import Success')
                                        ->body("Successfully imported '{$successCount}' records.")
                                        ->success()
                                        ->send();
                                }
                            } catch (\Exception $e) {
                                DB::rollBack();
                                Notification::make()
                                    ->title('Import Failed')
                                    ->body("No records were inserted. Error : {$e->getMessage()}")
                                    ->danger()
                                    ->send();
                            }
                        }
                    })
                    ->visible(function () {
                        return Filament::auth()->user()->can('view import invoice data validation');
                    }),
                ExportAction::make()
                    ->label('Export Invoice Data')
                    ->color('warning')
                    ->exporter(InvoiceDataValidationExporter::class)
                    ->visible(function () {
                        return Filament::auth()->user()->can('view export invoice data validation');
                    }),
            ]);
    }

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

    public static function getPages(): array
    {
        return [
            'index' => Pages\ListInvoiceDataValidations::route('/'),
            'create' => Pages\CreateInvoiceDataValidation::route('/create'),
            'view' => Pages\ViewInvoiceDataValidation::route('/{record}'),
            'edit' => Pages\EditInvoiceDataValidation::route('/{record}/edit'),
        ];
    }

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