<?php

namespace App\Filament\Resources;

use App\Filament\Resources\Concerns\HasModulePermissions;
use App\Filament\Resources\Concerns\HasStandardTableFeatures;
use App\Filament\Resources\ProductSerialResource\Pages\ListProductSerials;
use App\Filament\Resources\ProductSerialResource\Pages\ViewProductSerial;
use App\Filament\Support\Chip;
use App\Filament\Support\Perm;
use App\Filament\Support\StatusLookup;
use App\Models\Inventory\ProductSerial;
use App\Models\Inventory\SerialRepairHistory;
use App\Models\Lookups\Status;
use App\Services\AuditLog;
use App\Services\SerialService;
use Filament\Actions\Action;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;

/**
 * Ported from App\Http\Controllers\Isms\ProductSerialController +
 * SerialService (docs/migration-plan.md Phase 4). Read-only + status-change
 * actions — serials are only ever created via GRN confirmation, matching the
 * source (no create/edit route). "Complete Repair" resolves the serial's
 * most recent open (completed_at null) repair record, since the source's
 * route takes an explicit {repair} id from its own repair-history UI, which
 * this simpler action list doesn't reproduce 1:1 — same end effect
 * (SerialService::completeRepair() unchanged), simpler selection UI.
 */
class ProductSerialResource extends Resource
{
    use HasModulePermissions;
    use HasStandardTableFeatures;

    protected static ?string $model = ProductSerial::class;

    protected static string $permissionModuleKey = 'inventory_serials';

    protected static string|\BackedEnum|null $navigationIcon = Heroicon::OutlinedHashtag;

    protected static string|\UnitEnum|null $navigationGroup = 'Inventory';

    protected static ?string $navigationLabel = 'Serial Numbers';

    protected static ?int $navigationSort = 50;

    public static function form(Schema $schema): Schema
    {
        return $schema->components([]);
    }

    public static function table(Table $table): Table
    {
        return static::standardTableDefaults($table)
            ->recordUrl(static::standardRecordUrl())
            ->emptyStateHeading('No serial numbers yet')
            ->emptyStateDescription('Serial-tracked products will appear here once received.')
            ->columns([
                Chip::documentNumber('serial_number', 'Serial #')->searchable(),
                TextColumn::make('product.name')->searchable(),
                TextColumn::make('branch.name')->placeholder('—'),
                TextColumn::make('status.name')
                    ->badge()
                    ->color(fn (ProductSerial $record): string => StatusLookup::colorOfStatus($record->status)),
            ])
            ->filters([
                SelectFilter::make('product_id')->relationship('product', 'name'),
                SelectFilter::make('status_id')->label('Status')->options(fn () => StatusLookup::forContext(Status::CTX_PRODUCT_SERIAL)->pluck('name', 'id')),
            ])
            ->recordActions([
                Action::make('view')
                    ->url(fn (ProductSerial $record): string => ViewProductSerial::getUrl(['record' => $record]))
                    ->visible(fn (ProductSerial $record): bool => static::canView($record)),
                Action::make('mark_lost')
                    ->label('Mark Lost')
                    ->visible(fn (): bool => Perm::can('inventory_serials', 'manage'))
                    ->requiresConfirmation()
                    ->schema([Textarea::make('notes')->maxLength(500)])
                    ->action(function (ProductSerial $record, array $data): void {
                        app(SerialService::class)->markLost($record, $data['notes'] ?? '');
                        AuditLog::record('serial.lost', $record, ['serial_number' => $record->serial_number, 'notes' => $data['notes'] ?? null]);
                        Notification::make()->title('Serial marked as lost.')->success()->send();
                    }),
                Action::make('mark_damaged')
                    ->label('Mark Damaged')
                    ->visible(fn (): bool => Perm::can('inventory_serials', 'manage'))
                    ->requiresConfirmation()
                    ->schema([Textarea::make('notes')->maxLength(500)])
                    ->action(function (ProductSerial $record, array $data): void {
                        app(SerialService::class)->markDamaged($record, $data['notes'] ?? '');
                        AuditLog::record('serial.damaged', $record, ['serial_number' => $record->serial_number, 'notes' => $data['notes'] ?? null]);
                        Notification::make()->title('Serial marked as damaged.')->success()->send();
                    }),
                Action::make('write_off')
                    ->label('Write Off')
                    ->color('danger')
                    ->visible(fn (): bool => Perm::can('inventory_serials', 'manage'))
                    ->requiresConfirmation()
                    ->schema([Textarea::make('reason')->required()->maxLength(500)])
                    ->action(function (ProductSerial $record, array $data): void {
                        app(SerialService::class)->writeOff($record, $data['reason']);
                        AuditLog::record('serial.written_off', $record, ['serial_number' => $record->serial_number, 'reason' => $data['reason']]);
                        Notification::make()->title('Serial written off.')->success()->send();
                    }),
                Action::make('begin_repair')
                    ->label('Begin Repair')
                    ->visible(fn (ProductSerial $record): bool => Perm::can('inventory_serials', 'repair') && $record->status?->code !== Status::SERIAL_UNDER_REPAIR)
                    ->schema([
                        Textarea::make('description')->required()->maxLength(1000),
                        DatePicker::make('started_at')->required()->default(now()),
                        TextInput::make('repaired_by')->maxLength(100),
                        Textarea::make('notes')->maxLength(500),
                    ])
                    ->action(function (ProductSerial $record, array $data): void {
                        app(SerialService::class)->beginRepair($record, $data);
                        AuditLog::record('serial.repair_started', $record, ['serial_number' => $record->serial_number, 'description' => $data['description']]);
                        Notification::make()->title('Repair started.')->success()->send();
                    }),
                Action::make('complete_repair')
                    ->label('Complete Repair')
                    ->visible(fn (ProductSerial $record): bool => Perm::can('inventory_serials', 'repair') && $record->status?->code === Status::SERIAL_UNDER_REPAIR)
                    ->schema([
                        Select::make('outcome')->options([
                            'repaired' => 'Repaired',
                            'unrepairable' => 'Unrepairable',
                            'returned_to_customer' => 'Returned to Customer',
                        ])->required(),
                        Textarea::make('notes')->maxLength(500),
                    ])
                    ->action(function (ProductSerial $record, array $data): void {
                        $repair = SerialRepairHistory::where('product_serial_id', $record->id)
                            ->whereNull('completed_at')
                            ->latest('started_at')
                            ->first();

                        if (! $repair) {
                            Notification::make()->title('No open repair found for this serial.')->danger()->send();

                            return;
                        }

                        app(SerialService::class)->completeRepair($repair, $data['outcome'], $data['notes'] ?? null, (int) ($repair->branch_id ?? $record->branch_id ?? 0));
                        AuditLog::record('serial.repair_completed', $record, ['serial_number' => $record->serial_number, 'outcome' => $data['outcome']]);
                        Notification::make()->title('Repair completed.')->success()->send();
                    }),
            ]);
    }

    public static function getPages(): array
    {
        return [
            'index' => ListProductSerials::route('/'),
            'view' => ViewProductSerial::route('/{record}'),
        ];
    }
}
