<?php

namespace App\Filament\Resources;

use App\Filament\Exports\InvoiceInTransitExporter;
use App\Filament\Resources\InvoiceInTransitResource\Pages;
use App\Models\InvoiceInTransit;
use App\Models\Plant;
use Filament\Facades\Filament;
use Filament\Forms;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Form;
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 Maatwebsite\Excel\Facades\Excel;
use Storage;

class InvoiceInTransitResource extends Resource
{
    protected static ?string $model = InvoiceInTransit::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')
                    ->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('receiving_plant')
                    ->label('Receiving Plant'),
                Forms\Components\TextInput::make('receiving_plant_name')
                    ->label('Receiving Plant Name'),
                Forms\Components\TextInput::make('invoice_number')
                    ->label('Invoice Number'),
                Forms\Components\TextInput::make('invoice_date')
                    ->label('Invoice Date'),
                Forms\Components\TextInput::make('item_code')
                    ->label('Item Code'),
                Forms\Components\TextInput::make('description')
                    ->label('Description'),
                Forms\Components\TextInput::make('quantity')
                    ->label('Quantity')
                    ->numeric()
                    ->default(null),
                Forms\Components\TextInput::make('transport_name')
                    ->label('Transport Name'),
                Forms\Components\TextInput::make('lr_bl_aw_number')
                    ->label('LR/BL/AW Number'),
                Forms\Components\TextInput::make('lr_bl_aw_date')
                    ->label('LR/BL/AW Date'),
                Forms\Components\TextInput::make('pending_days')
                    ->label('Pending Days'),
                Forms\Components\TextInput::make('obd_number')
                    ->label('OBD Number'),
                Forms\Components\TextInput::make('obd_date')
                    ->label('OBD Date'),
                Forms\Components\TextInput::make('shipment_weight')
                    ->label('Shipment Weight'),
                Forms\Components\TextInput::make('unit_price')
                    ->label('Unit Price'),
                Forms\Components\TextInput::make('net_value')
                    ->label('Net value'),
                Forms\Components\TextInput::make('total_item_amount')
                    ->label('Total Item Amount'),
                Forms\Components\TextInput::make('tax_amount')
                    ->label('Tax Amount'),
                Forms\Components\TextInput::make('transport_mode')
                    ->label('Transport Mode'),
                Forms\Components\TextInput::make('vehicle_number')
                    ->label('Vehicle Number'),
                Forms\Components\TextInput::make('e_waybill_number')
                    ->label('E Way Bill Number'),
                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.name')
                    ->label('Plant')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('receiving_plant')
                    ->label('Receiving Plant')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('receiving_plant_name')
                    ->label('Receiving Plant Name')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('invoice_number')
                    ->label('Invoice Number')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('invoice_date')
                    ->label('Invoice Date')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('item_code')
                    ->label('Item Code')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('description')
                    ->label('Description')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('quantity')
                    ->label('Quantity')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('transport_name')
                    ->label('Transport Name')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('lr_bl_aw_number')
                    ->label('LR/BL/AW Number')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('lr_bl_aw_date')
                    ->label('LR/BL/AW Date')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('pending_days')
                    ->label('Pending Days')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('obd_number')
                    ->label('OBD Number')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('obd_date')
                    ->label('OBD Date')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('shipment_weight')
                    ->label('Shipment Weight')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('unit_price')
                    ->label('Unit Price')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('net_value')
                    ->label('Net value')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('total_item_amount')
                    ->label('Total Item Amount')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('tax_amount')
                    ->label('Tax Amount')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('transport_mode')
                    ->label('Transport Mode')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('vehicle_number')
                    ->label('Vehicle Number')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('e_waybill_number')
                    ->label('E Way Bill Number')
                    ->alignCenter()
                    ->searchable()
                    ->sortable(),
                Tables\Columns\TextColumn::make('created_at')
                    ->dateTime()
                    ->sortable()
                    ->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('updated_at')
                    ->dateTime()
                    ->sortable()
                    ->toggleable(isToggledHiddenByDefault: true),
                Tables\Columns\TextColumn::make('deleted_at')
                    ->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 In Transit')
                    ->label('Import Invoice In Transit')
                    ->form([
                        FileUpload::make('invoice_in_transit_file')
                            ->label('Import Invoice In Transit')
                            ->preserveFilenames()
                            ->storeFiles(false)
                            ->reactive()
                            ->required()
                            ->disk('local')
                            ->directory('uploads/InvoiceInTransit'),
                    ])
                    ->action(function (array $data) {
                        InvoiceInTransit::truncate();
                        $uploadedFile = $data['invoice_in_transit_file'];

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

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

                        $operatorName = $user->name;

                        // Get original filename
                        $originalName = $uploadedFile->getClientOriginalName();

                        $path = $uploadedFile->storeAs('uploads/InvoiceInTransit', $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 Master Data' file to proceed..!")
                                    ->danger()
                                    ->send();

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

                                return;
                            }

                            $invalidPlantCode = [];
                            $invalidPlantCo = [];
                            $invalidPlaCoFound = [];
                            $invalidRecPlant = [];
                            $invalidRecPlantName = [];
                            $invalidInvNo = [];
                            $invalidInvDt = [];
                            $invalidICode = [];
                            $invalidDesc = [];
                            $invalidQty = [];
                            $invalidTransportName = [];
                            $invalidLRBLAWNo = [];
                            $invalidLRBLAWDt = [];
                            $invalidPenDay = [];

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

                                $plantCode = trim($row[0]);
                                $receivingPlant = trim($row[2]);
                                $receivingPlantName = trim($row[3]);
                                $invoiceNo = trim($row[4]);
                                $invoiceDt = trim($row[5]);
                                $itemCode = trim($row[6]);
                                $des = trim($row[7]);
                                $quantity = trim($row[8]);
                                $transportName = trim($row[9]);
                                $LRBAWNo = trim($row[10]);
                                $LRBAWDt = trim($row[11]);
                                $pendingDays = trim($row[12]);

                                if (empty($plantCode)) {
                                    $invalidPlantCode[] = "Row {$index}";
                                }
                                if (empty($receivingPlant)) {
                                    $invalidRecPlant[] = "Row {$index}";
                                }
                                if (empty($receivingPlantName)) {
                                    $invalidRecPlantName[] = "Row {$index}";
                                }
                                if (empty($invoiceNo)) {
                                    $invalidInvNo[] = "Row {$index}";
                                }
                                if (empty($invoiceDt)) {
                                    $invalidInvDt[] = "Row {$index}";
                                }
                                if (empty($itemCode)) {
                                    $invalidICode[] = "Row {$index}";
                                }
                                if (empty($des)) {
                                    $invalidDesc[] = "Row {$index}";
                                }
                                if (empty($quantity)) {
                                    $invalidQty[] = "Row {$index}";
                                }
                                if (empty($transportName)) {
                                    $invalidTransportName[] = "Row {$index}";
                                }
                                // if (empty($LRBAWNo)) {
                                //     $invalidLRBLAWNo[] = "Row {$index}";
                                // }
                                // if (empty($LRBAWDt)) {
                                //     $invalidLRBLAWDt[] = "Row {$index}";
                                // }
                                if (empty($pendingDays)) {
                                    $invalidPenDay[] = "Row {$index}";
                                }

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

                                if($LRBAWNo){
                                    if(strlen($LRBAWNo) < 2){
                                        $invalidLRBLAWNo[] = $LRBAWNo;
                                    }
                                }

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

                                // $plantId = $plant->id;

                            }

                            if (! empty($invalidPlantCode) || ! empty($invalidRecPlant) || ! empty($invalidRecPlantName) || ! empty($invalidInvNo) || ! empty($invalidInvDt) || ! empty($invalidICode) || ! empty($invalidDesc) || ! empty($invalidQty) || ($invalidTransportName) || ! empty($invalidPenDay)) {
                                $errorMsg = '';

                                if (! empty($invalidPlantCode)) {
                                    $errorMsg .= 'Missing Receiving Plant Code in rows: '.implode(', ', $invalidPlantCode).'<br>';
                                }
                                if (! empty($invalidRecPlant)) {
                                    $errorMsg .= 'Missing Receiving Plant in rows: '.implode(', ', $invalidRecPlant).'<br>';
                                }
                                if (! empty($invalidRecPlantName)) {
                                    $errorMsg .= 'Missing Receiving Plant Name in rows: '.implode(', ', $invalidRecPlantName).'<br>';
                                }
                                if (! empty($invalidInvNo)) {
                                    $errorMsg .= 'Missing Invoice Number in rows: '.implode(', ', $invalidInvNo).'<br>';
                                }
                                if (! empty($invalidInvDt)) {
                                    $errorMsg .= 'Missing Invoice Dates in rows: '.implode(', ', $invalidInvDt).'<br>';
                                }
                                if (! empty($invalidICode)) {
                                    $errorMsg .= 'Missing Item Code in rows: '.implode(', ', $invalidICode).'<br>';
                                }
                                if (! empty($invalidDesc)) {
                                    $errorMsg .= 'Missing Item Description in rows: '.implode(', ', $invalidDesc).'<br>';
                                }
                                if (! empty($invalidQty)) {
                                    $errorMsg .= 'Missing Quantity in rows: '.implode(', ', $invalidQty).'<br>';
                                }
                                if (! empty($invalidTransportName)) {
                                    $errorMsg .= 'Missing Transport Name in rows: '.implode(', ', $invalidTransportName).'<br>';
                                }
                                // if (! empty($invalidLRBLAWNo)) {
                                //     $errorMsg .= 'Missing Receiving Plant Name in rows: '.implode(', ', $invalidLRBLAWNo).'<br>';
                                // }
                                // if (! empty($invalidLRBLAWDt)) {
                                //     $errorMsg .= 'Missing Transit Days in rows: '.implode(', ', $invalidLRBLAWDt).'<br>';
                                // }
                                if (! empty($invalidPenDay)) {
                                    $errorMsg .= 'Missing Pending Days in rows: '.implode(', ', $invalidPenDay).'<br>';
                                }

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

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

                                return;
                            }

                            if (! empty($invalidPlantCo)) {
                                $invalidPlantCode = array_unique($invalidPlantCo);
                                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;
                            }

                            if (! 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($invalidLRBLAWNo)) {
                                $invalidLRBLAWNo = array_unique($invalidLRBLAWNo);
                                Notification::make()
                                    ->title('Invalid LR/BL/AW Number')
                                    ->body('LR/BL/AW Number should contain length minimum 2 digits:<br>'.implode(', ', $invalidLRBLAWNo))
                                    ->danger()
                                    ->send();
                                if ($disk->exists($path)) {
                                    $disk->delete($path);
                                }
                                return;
                            }

                            $mandatoryColumns = 23;

                            $firstRow = $rows[0] ?? [];

                            if (count($firstRow) < $mandatoryColumns) {
                                Notification::make()
                                    ->title('Invalid Excel Format')
                                    ->body('Few columns not found. Columns A to W are mandatory.')
                                    ->danger()
                                    ->persistent()
                                    ->send();
                                return;
                            }

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

                                $plantCode = trim($row[0]);
                                $receivingPlant = trim($row[2]);
                                $receivingPlantName = trim($row[3]);
                                $invoiceNo = trim($row[4]);
                                $invoiceDt = trim($row[5]);
                                $itemCode = trim($row[6]);
                                $des = trim($row[7]);
                                $quantity = trim($row[8]);
                                $transportName = trim($row[9]);
                                $LRBAWNo = trim($row[10]);
                                $LRBAWDt = trim($row[11]);
                                $pendingDays = trim($row[12]);
                                $OBDNumber = trim($row[13]);
                                $OBDDate = trim($row[14]);
                                $ShipmentWeight = trim($row[15]);
                                $UnitPrice = trim($row[16]);
                                $NetValue = trim($row[17]);
                                $TotalItemAmount = trim($row[18]);
                                $TaxAmount = trim($row[19]);
                                $TransportMode = trim($row[20]);
                                $VehicleNumber = trim($row[21]);
                                $EWayBillNumber = trim($row[22]);

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

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

                                $rowNumber = $index + 1;
                                if ($LRBAWNo == '' || $LRBAWDt == '') {
                                    // $missedInvoices[] = $invoiceNo;
                                    // $missedInvoices[$invoiceNo][] = $index + 1;
                                    // continue;
                                    $key = $invoiceNo ?: 'Row '.$rowNumber;
                                    $missedInvoices[$key][$rowNumber] = true;
                                    continue;
                                }

                                $inserted = InvoiceInTransit::create([
                                    'plant_id' => $plant->id,
                                    'receiving_plant' => $receivingPlant,
                                    'receiving_plant_name' => $receivingPlantName,
                                    'invoice_number' => $invoiceNo,
                                    'invoice_date' => $formattedDate,
                                    'item_code' => $itemCode,
                                    'description' => $des,
                                    'quantity' => $quantity,
                                    'transport_name' => $transportName,
                                    'lr_bl_aw_number' => $LRBAWNo,
                                    'lr_bl_aw_date' => $formattedDt,
                                    'pending_days' => $pendingDays,
                                    'obd_number' => $OBDNumber,
                                    'obd_date' => $formatted,
                                    'shipment_weight' => $ShipmentWeight,
                                    'unit_price' => $UnitPrice,
                                    'net_value' => $NetValue,
                                    'total_item_amount' => $TotalItemAmount,
                                    'tax_amount' => $TaxAmount,
                                    'transport_mode' => $TransportMode,
                                    'vehicle_number' => $VehicleNumber,
                                    'e_waybill_number' => $EWayBillNumber,
                                    'created_at' => now(),
                                    'created_by' => $operatorName,
                                ]);
                            }

                            $formattedMissed = [];

                            if (!empty($missedInvoices)) {
                                $formattedMissed = array_map(
                                    fn($rows, $invoice) =>
                                        $invoice . ' (Row: ' . implode(', ', array_keys($rows)) . ')',
                                    $missedInvoices,
                                    array_keys($missedInvoices)
                                );
                            }
                            if ($inserted) {
                                $message = "Invoice in transit uploaded successfully!";

                                if (!empty($formattedMissed)) {
                                    $message .= "\n\nSkipped Invoices (Missing LR/Date):\n"
                                            . implode("\n", $formattedMissed);
                                }

                                Notification::make()
                                    ->title('Upload Completed')
                                    ->body($message)
                                    ->success()
                                    ->send();

                                return;
                            } else {
                                Notification::make()
                                    ->title('Insertion Failed')
                                    ->body('Invoice in transit upload failed!')
                                    ->success()
                                    ->send();
                                return;
                            }
                        }
                    })
                    ->visible(function () {
                        return Filament::auth()->user()->can('view import invoice in transit');
                    }),
                ExportAction::make()
                    ->label('Export Invoice In Transit')
                    ->color('warning')
                    ->exporter(InvoiceInTransitExporter::class)
                    ->visible(function () {
                        return Filament::auth()->user()->can('view export invoice in transit');
                    }),
            ]);
    }

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

    public static function getPages(): array
    {
        return [
            'index' => Pages\ListInvoiceInTransits::route('/'),
            'create' => Pages\CreateInvoiceInTransit::route('/create'),
            'view' => Pages\ViewInvoiceInTransit::route('/{record}'),
            'edit' => Pages\EditInvoiceInTransit::route('/{record}/edit'),
        ];
    }

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