<?php

namespace App\Filament\Resources;

use App\Filament\Resources\Concerns\AssertsBranchAccess;
use App\Filament\Resources\Concerns\HasModulePermissions;
use App\Filament\Resources\Concerns\HasStandardTableFeatures;
use App\Filament\Resources\PurchaseOrderResource\Pages\CreatePurchaseOrder;
use App\Filament\Resources\PurchaseOrderResource\Pages\ListPurchaseOrders;
use App\Filament\Resources\PurchaseOrderResource\Pages\ViewPurchaseOrder;
use App\Filament\Support\Chip;
use App\Filament\Support\Perm;
use App\Filament\Support\ProductSelect;
use App\Filament\Support\RelationSelect;
use App\Filament\Support\StatusLookup;
use App\Models\Catalog\Product;
use App\Models\Lookups\Status;
use App\Models\Purchasing\PurchaseOrder;
use App\Services\CurrentContext;
use App\Services\PurchaseOrderService;
use App\Support\Quantity;
use Filament\Actions\Action;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Notifications\Notification;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Filters\SelectFilter;
use Filament\Tables\Table;
use RuntimeException;

/**
 * Ported from App\Http\Controllers\Isms\PurchaseOrderController +
 * PurchaseOrderService (docs/migration-plan.md Phase 3). The source app has
 * NO update/edit route for purchase orders — only create, show, send
 * (draft→sent), and cancel (blocked once fully received). This resource
 * deliberately has no EditRecord page, matching that exactly: a PO's lines
 * are fixed at creation, and its status only moves through
 * send()/cancel()/applyGrnReceipt() (the last driven by GrnController, not
 * a manual edit). branch_id access is re-checked server-side on create via
 * CurrentContext::canAccessBranch(), matching the source controller's
 * abort_unless — the form's branch Select only offers active branches, but
 * that's a UI convenience, not the real gate.
 */
class PurchaseOrderResource extends Resource
{
    use AssertsBranchAccess;
    use HasModulePermissions;
    use HasStandardTableFeatures;

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

    protected static string $permissionModuleKey = 'isms_purchase_orders';

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

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

    protected static ?string $navigationLabel = 'Purchase Orders';

    protected static ?int $navigationSort = 0;

    public static function form(Schema $schema): Schema
    {
        return $schema->components([
            Section::make('Details')->schema([
                RelationSelect::make(
                    name: 'supplier_id',
                    relationship: 'supplier',
                    titleAttribute: 'name',
                    createPermission: 'isms_suppliers.create',
                )->label('Supplier')->required(),
                RelationSelect::make(
                    name: 'branch_id',
                    relationship: 'branch',
                    titleAttribute: 'name',
                    modifyQueryUsing: fn ($query) => $query->where('is_active', true),
                )->label('Branch')->required(),
                DatePicker::make('expected_date'),
                Textarea::make('notes')->maxLength(1000)->columnSpanFull(),
            ]),

            Section::make('Items')->schema([
                Repeater::make('items')
                    ->schema([
                        ProductSelect::standalone(
                            modifyQueryUsing: fn ($query) => $query->where('is_active', true),
                        )->label('Product')->required()->live(),
                        // No unit picker — the product's own base unit applies
                        // automatically (HasDefaultUnitFromProduct).
                        TextInput::make('quantity')
                            ->numeric()->required()->minValue(0.01)->maxValue(1000000)
                            ->suffix(fn (Get $get): ?string => Quantity::unitLabel(Product::find($get('product_id'))?->baseUnit)),
                        TextInput::make('unit_cost')->numeric()->minValue(0)->maxValue(99999999.99)->prefix('Rs.'),
                    ])
                    // Same reasoning as GrnResource's items repeater: this Section
                    // is one of two side by side on the page, so it only ever gets
                    // roughly half the viewport — 4 columns cramped a searchable
                    // product picker into ~140px.
                    ->columns(2)
                    ->defaultItems(1)
                    ->minItems(1)
                    ->addActionLabel('Add item')
                    ->columnSpanFull(),
            ]),
        ]);
    }

    public static function table(Table $table): Table
    {
        return static::standardTableDefaults($table)
            ->recordUrl(static::standardRecordUrl())
            ->emptyStateHeading('No purchase orders yet')
            ->emptyStateDescription('Send a PO to a supplier to start the purchasing trail.')
            ->columns([
                Chip::documentNumber('po_number', 'PO #')->searchable()->sortable(),
                TextColumn::make('supplier.name')->searchable()->sortable(),
                TextColumn::make('branch.name'),
                TextColumn::make('items_count')->label('Items')->counts('items'),
                TextColumn::make('status.name')
                    ->badge()
                    ->color(fn (PurchaseOrder $record): string => StatusLookup::colorOfStatus($record->status)),
                TextColumn::make('created_at')->dateTime()->sortable(),
            ])
            ->defaultSort('created_at', 'desc')
            ->filters([
                SelectFilter::make('supplier_id')->relationship('supplier', 'name'),
                SelectFilter::make('status_id')->label('Status')->options(fn () => StatusLookup::forContext(Status::CTX_PURCHASE_ORDER)->pluck('name', 'id')),
            ])
            ->recordActions([
                Action::make('view')
                    ->url(fn (PurchaseOrder $record): string => ViewPurchaseOrder::getUrl(['record' => $record]))
                    ->visible(fn (PurchaseOrder $record): bool => static::canView($record)),
                Action::make('send')
                    ->label('Send via WhatsApp')
                    ->icon(Heroicon::OutlinedPaperAirplane)
                    // The send flow is a wa.me deep link: the PO (header +
                    // lines) is pre-filled into a WhatsApp chat with the
                    // supplier. No supplier phone on file → no way to send
                    // → the option is hidden entirely.
                    ->visible(fn (PurchaseOrder $record): bool => Perm::can('isms_purchase_orders', 'send') && $record->isDraft() && filled($record->supplier?->phone))
                    ->action(function (Action $action, PurchaseOrder $record): void {
                        try {
                            $service = app(PurchaseOrderService::class);
                            $service->send($record);

                            $link = $service->whatsappLink($record->fresh(['supplier']));
                            $action->redirect($link);
                        } catch (RuntimeException $e) {
                            Notification::make()->title($e->getMessage())->danger()->send();
                        }
                    }),
                Action::make('cancel')
                    ->visible(fn (PurchaseOrder $record): bool => Perm::can('isms_purchase_orders', 'cancel') && $record->status?->code !== Status::PO_CANCELLED && $record->status?->code !== Status::PO_RECEIVED)
                    ->requiresConfirmation()
                    ->schema([
                        Textarea::make('reason')->required()->maxLength(500),
                    ])
                    ->action(function (PurchaseOrder $record, array $data): void {
                        try {
                            app(PurchaseOrderService::class)->cancel($record, $data['reason']);
                            Notification::make()->title('Purchase order cancelled.')->success()->send();
                        } catch (RuntimeException $e) {
                            Notification::make()->title($e->getMessage())->danger()->send();
                        }
                    }),
            ]);
    }

    public static function getPages(): array
    {
        return [
            'index' => ListPurchaseOrders::route('/'),
            'create' => CreatePurchaseOrder::route('/create'),
            'view' => ViewPurchaseOrder::route('/{record}'),
        ];
    }
}
