<?php

declare(strict_types=1);

namespace App\Filament\Resources\DberpPurchaseReturns\RelationManagers;

use App\Business\Inventory\Enums\InventoryDocumentStatus;
use App\Filament\Support\DberpFilamentNumberFields;
use App\Models\DberpPurchaseOrderItem;
use App\Models\DberpPurchaseReceiptOrderItem;
use App\Models\DberpPurchaseReturnOrder;
use App\Support\DberpDocumentLineOutboundSerialNumberFormFields;
use App\Support\DberpDocumentLinePresentation;
use App\Support\DberpDocumentLineSpecPresentation;
use App\Support\DberpDocumentLineUnitFormFields;
use App\Support\DberpLineProductSkuFormFields;
use App\Support\DberpNumberFormatter;
use App\Support\DberpProductInventoryRefinementFormFields;
use App\Support\DberpProductSkuSelectOptions;
use Filament\Actions\CreateAction;
use Filament\Actions\DeleteAction;
use Filament\Actions\EditAction;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Schemas\Components\Utilities\Set;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Model;

class ItemsRelationManager extends RelationManager
{
    protected static string $relationship = 'items';

    public static function getTitle(Model $ownerRecord, string $pageClass): string
    {
        return __('dberp.relations.purchase_return_items');
    }

    protected static function getModelLabel(): ?string
    {
        return __('dberp.relations.purchase_return_items');
    }

    protected static function getPluralModelLabel(): ?string
    {
        return __('dberp.relations.purchase_return_items');
    }

    public function form(Schema $schema): Schema
    {
        $locksLine = fn (): bool => DberpDocumentLineUnitFormFields::ownerStatusLocksDocumentLineFields(
            $this->getOwnerRecord()->status,
            InventoryDocumentStatus::Draft->value,
        );
        $resolveProduct = DberpDocumentLineUnitFormFields::resolveProductFromProductIdField('product_id');

        return $schema
            ->components(array_merge([
                Select::make('purchase_order_item_id')
                    ->label(__('dberp.fields.purchase_order_item'))
                    ->options(function (): array {
                        /** @var DberpPurchaseReturnOrder $owner */
                        $owner = $this->getOwnerRecord();
                        $orderId = $owner->purchase_order_id ?? $owner->purchaseReceiptOrder?->purchase_order_id;

                        if ($orderId === null) {
                            return [];
                        }

                        return DberpPurchaseOrderItem::query()
                            ->with('product')
                            ->where('order_id', $orderId)
                            ->orderBy('sort_order')
                            ->orderBy('id')
                            ->get()
                            ->mapWithKeys(fn (DberpPurchaseOrderItem $item): array => [
                                $item->getKey() => sprintf('%s / %s / 可退 %s', (string) $item->product?->code, (string) $item->product?->name, DberpNumberFormatter::quantity((float) $item->received_quantity - (float) $item->returned_quantity)),
                            ])
                            ->all();
                    })
                    ->searchable()
                    ->preload()
                    ->live()
                    ->afterStateUpdated(function (Set $set, Get $get) use ($resolveProduct): void {
                        DberpLineProductSkuFormFields::applyFromPurchaseOrderItemSelection($set, (int) ($get('purchase_order_item_id') ?? 0) ?: null);
                        DberpDocumentLineUnitFormFields::syncUnitIdFromResolvedProduct($set, $get, $resolveProduct);
                    })
                    ->required(),
                Select::make('purchase_receipt_item_id')
                    ->label(__('dberp.fields.purchase_receipt_item'))
                    ->options(function (): array {
                        /** @var DberpPurchaseReturnOrder $owner */
                        $owner = $this->getOwnerRecord();

                        if ($owner->purchase_receipt_order_id === null) {
                            return [];
                        }

                        return DberpPurchaseReceiptOrderItem::query()
                            ->with('product')
                            ->where('order_id', $owner->purchase_receipt_order_id)
                            ->orderBy('sort_order')
                            ->orderBy('id')
                            ->get()
                            ->mapWithKeys(fn (DberpPurchaseReceiptOrderItem $item): array => [
                                $item->getKey() => sprintf('%s / %s / 可退 %s', (string) $item->product?->code, (string) $item->product?->name, DberpNumberFormatter::quantity((float) $item->received_quantity - (float) $item->returned_quantity)),
                            ])
                            ->all();
                    })
                    ->searchable()
                    ->preload()
                    ->live()
                    ->afterStateUpdated(function (Set $set, Get $get) use ($resolveProduct): void {
                        $rid = (int) ($get('purchase_receipt_item_id') ?? 0);
                        if ($rid > 0) {
                            DberpLineProductSkuFormFields::applyFromPurchaseReceiptItemSelection($set, $rid);
                            DberpDocumentLineUnitFormFields::syncUnitIdFromResolvedProduct($set, $get, $resolveProduct);
                        }
                    }),
                DberpDocumentLineUnitFormFields::wireProductDriver(
                    DberpProductSkuSelectOptions::configurePurchasableProductSelect(
                        Select::make('product_id')
                            ->label(__('dberp.fields.product'))
                            ->required(),
                    ),
                    $resolveProduct,
                    function (Set $set, Get $get): void {
                        DberpLineProductSkuFormFields::syncAfterProductIdChanged($set, $get, 'product_id');
                        DberpDocumentLineOutboundSerialNumberFormFields::resetLineSerialState($set);
                    },
                ),
            ], DberpLineProductSkuFormFields::specificationComboFields('product_id', $locksLine), DberpDocumentLineUnitFormFields::blocks(
                $resolveProduct,
                false,
                $locksLine,
            ), DberpDocumentLineUnitFormFields::withApproxBasePreviewAfterQuantityField([
                ...DberpProductInventoryRefinementFormFields::outboundSourceBatchAndBatchNoFields(
                    Select::make('source_batch_id')
                        ->label(__('dberp.fields.source_batch'))
                        ->options(function (Get $get): array {
                            /** @var DberpPurchaseReturnOrder $owner */
                            $owner = $this->getOwnerRecord();
                            $productId = (int) ($get('product_id') ?? 0);

                            if ($owner->warehouse_id === null || $productId <= 0) {
                                return [];
                            }

                            return DberpProductInventoryRefinementFormFields::outboundSourceBatchSelectOptions(
                                (int) $owner->warehouse_id,
                                $productId,
                                onlyPositiveAvailableQuantity: false,
                            );
                        })
                        ->searchable()
                        ->preload(),
                    TextInput::make('batch_no')
                        ->label(__('dberp.fields.batch_no'))
                        ->maxLength(64),
                    $resolveProduct,
                    fn (): int => (int) ($this->getOwnerRecord()->warehouse_id ?? 0),
                ),
                DberpProductInventoryRefinementFormFields::constrainExpiryField(
                    DatePicker::make('production_date')
                        ->label(__('dberp.fields.production_date')),
                    $resolveProduct,
                ),
                DberpProductInventoryRefinementFormFields::constrainExpiryField(
                    DatePicker::make('expiry_date')
                        ->label(__('dberp.fields.expiry_date')),
                    $resolveProduct,
                ),
                DberpProductInventoryRefinementFormFields::constrainExpiryField(
                    TextInput::make('shelf_life_days')
                        ->label(__('dberp.fields.shelf_life_days'))
                        ->numeric()
                        ->minValue(0)
                        ->default(0),
                    $resolveProduct,
                ),
                DberpDocumentLineOutboundSerialNumberFormFields::documentLineQuantityTrimsSerialNumbers(
                    DberpFilamentNumberFields::documentLineQuantityInput(
                        TextInput::make('return_quantity')
                            ->label(__('dberp.document_line.entry_quantity'))
                            ->required(),
                    ),
                    $resolveProduct,
                ),
                ...DberpDocumentLineOutboundSerialNumberFormFields::outboundSerialNumberFields(
                    $resolveProduct,
                    fn (): int => (int) ($this->getOwnerRecord()->warehouse_id ?? 0),
                    fn (Get $get): int => (int) ($get('source_batch_id') ?? 0),
                    'return_quantity',
                ),
                DberpFilamentNumberFields::moneyInput(
                    TextInput::make('unit_price')
                        ->label(__('dberp.fields.unit_price'))
                        ->default(0)
                        ->required(),
                    withHelperText: false,
                    minValue: 0.0,
                ),
                TextInput::make('sort_order')
                    ->label(__('dberp.fields.sort_order'))
                    ->numeric()
                    ->default(0)
                    ->required(),
                Textarea::make('remark')
                    ->label(__('dberp.fields.remark'))
                    ->rows(2)
                    ->columnSpanFull(),
            ], 'return_quantity', $resolveProduct)));
    }

    public function table(Table $table): Table
    {
        return $table
            ->modifyQueryUsing(fn ($query) => $query->with(DberpDocumentLineSpecPresentation::eagerLoadsForDocumentLines(['baseUnit', 'auxiliaryUnit'])))
            ->recordTitleAttribute('product.name')
            ->defaultSort('sort_order', 'asc')
            ->columns([
                TextColumn::make('product.code')
                    ->label(__('dberp.fields.product_code')),
                TextColumn::make('product.name')
                    ->label(__('dberp.fields.product_name')),
                TextColumn::make('document_line_spec_summary')
                    ->label(__('dberp.fields.document_line_product_spec_combo'))
                    ->state(fn (Model $record): string => DberpDocumentLineSpecPresentation::lineSpecSummary($record))
                    ->wrap(),
                TextColumn::make('document_line_spec_code')
                    ->label(__('dberp.fields.document_line_spec_code'))
                    ->state(fn (Model $record): string => DberpDocumentLineSpecPresentation::lineSpecCode($record)),
                TextColumn::make('document_line_spec_abstract')
                    ->label(__('dberp.fields.document_line_spec_summary'))
                    ->state(fn (Model $record): string => DberpDocumentLineSpecPresentation::lineSpecAbstract($record))
                    ->wrap()
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('unit_name')
                    ->label(__('dberp.fields.document_line_entered_unit')),
                TextColumn::make('return_quantity')
                    ->label(__('dberp.fields.document_line_entered_quantity'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::quantity($state)),
                TextColumn::make('document_line_primary_base_quantity')
                    ->label(__('dberp.fields.document_line_primary_base_quantity'))
                    ->state(fn ($record): string => DberpDocumentLinePresentation::primaryBaseQuantityDisplay($record))
                    ->toggleable(),
                TextColumn::make('document_line_conversion_snapshot')
                    ->label(__('dberp.fields.document_line_conversion_snapshot'))
                    ->state(fn ($record): string => DberpDocumentLinePresentation::conversionSnapshotLine($record))
                    ->wrap()
                    ->toggleable(isToggledHiddenByDefault: true),
                DberpProductInventoryRefinementFormFields::constrainBatchColumn(
                    TextColumn::make('batch_no')
                        ->label(__('dberp.fields.batch_no'))
                        ->toggleable(),
                ),
                DberpProductInventoryRefinementFormFields::constrainSerialColumn(
                    TextColumn::make('serial_numbers_count')
                        ->label(__('dberp.fields.serial_number_count'))
                        ->state(fn ($record): int => count($record->serial_numbers ?? []))
                        ->toggleable(isToggledHiddenByDefault: true),
                ),
                TextColumn::make('unit_price')
                    ->label(__('dberp.fields.unit_price'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::price($state)),
                TextColumn::make('return_amount')
                    ->label(__('dberp.fields.return_amount'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::money($state)),
                TextColumn::make('sort_order')
                    ->label(__('dberp.fields.sort_order')),
            ])
            ->headerActions([
                CreateAction::make()
                    ->mutateDataUsing(fn (array $data): array => DberpProductInventoryRefinementFormFields::finalizeOutboundDocumentLineFormData($data))
                    ->visible(fn (): bool => $this->getOwnerRecord()->status === InventoryDocumentStatus::Draft->value),
            ])
            ->recordActions([
                EditAction::make()
                    ->mutateDataUsing(fn (array $data): array => DberpProductInventoryRefinementFormFields::finalizeOutboundDocumentLineFormData($data))
                    ->visible(fn (): bool => $this->getOwnerRecord()->status === InventoryDocumentStatus::Draft->value),
                DeleteAction::make()
                    ->visible(fn (): bool => $this->getOwnerRecord()->status === InventoryDocumentStatus::Draft->value),
            ]);
    }
}
