<?php

declare(strict_types=1);

namespace App\Filament\Resources\DberpPurchaseOrders\RelationManagers;

use App\Business\Purchase\Enums\PurchaseOrderItemExecutionStatus;
use App\Business\Purchase\Enums\PurchaseOrderStatus;
use App\Business\Purchase\PurchaseOrderOverviewService;
use App\Business\Purchase\PurchaseOrderService;
use App\Filament\Support\DberpFilamentNumberFields;
use App\Models\DberpPurchaseInquiryQuote;
use App\Models\DberpPurchaseOrderItem;
use App\Support\DberpDocumentLineBulkProductAddHeaderActions;
use App\Support\DberpDocumentLinePresentation;
use App\Support\DberpDocumentLineProductPickerFormFields;
use App\Support\DberpDocumentLineSpecPresentation;
use App\Support\DberpDocumentLineUnitFormFields;
use App\Support\DberpLineProductSkuFormFields;
use App\Support\DberpNumberFormatter;
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\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_order_items');
    }

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

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

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

        return $schema
            ->components(DberpDocumentLineProductPickerFormFields::purchasableTwoStepComponents(
                lineDisabled: $locksLine,
                quantityField: 'quantity',
                restrictToBaseInventoryUnit: false,
                afterSpecBlocks: [
                    Select::make('source_inquiry_quote_id')
                        ->label(__('dberp.fields.source_inquiry_quote'))
                        ->options(fn (): array => DberpPurchaseInquiryQuote::query()
                            ->orderByDesc('quote_date')
                            ->orderByDesc('id')
                            ->get()
                            ->mapWithKeys(fn (DberpPurchaseInquiryQuote $quote): array => [
                                $quote->getKey() => trim($quote->code.' / '.($quote->supplier_name_snapshot ?: $quote->supplier?->name ?: '-').' / '.($quote->product_name_snapshot ?: $quote->product?->name ?: '-').' / '.(string) $quote->unit_price),
                            ])
                            ->all())
                        ->disabled(fn (?DberpPurchaseOrderItem $record): bool => $this->getOwnerRecord()->status !== PurchaseOrderStatus::Draft->value
                            || $this->orderItemLocksSourceFields($record))
                        ->searchable()
                        ->preload(),
                ],
                afterUnitBlocks: [
                    TextInput::make('external_sku')
                        ->label(__('dberp.fields.external_sku'))
                        ->maxLength(128)
                        ->disabled(fn (): bool => $this->getOwnerRecord()->status !== PurchaseOrderStatus::Draft->value),
                    DberpFilamentNumberFields::documentLineQuantityInput(
                        TextInput::make('quantity')
                            ->label(__('dberp.fields.ordered_quantity'))
                            ->disabled(fn (?DberpPurchaseOrderItem $record): bool => $this->getOwnerRecord()->status !== PurchaseOrderStatus::Draft->value
                                || $this->orderItemLocksSourceFields($record))
                            ->required(),
                    ),
                    DberpFilamentNumberFields::moneyInput(
                        TextInput::make('unit_price')
                            ->label(__('dberp.fields.unit_price'))
                            ->default(0)
                            ->disabled(fn (): bool => $this->getOwnerRecord()->status !== PurchaseOrderStatus::Draft->value)
                            ->required(),
                        withHelperText: false,
                        minValue: 0.0,
                    ),
                    DatePicker::make('expected_arrival_date')
                        ->label(__('dberp.fields.expected_arrival_date'))
                        ->disabled(fn (): bool => in_array($this->getOwnerRecord()->status, [PurchaseOrderStatus::Closed->value, PurchaseOrderStatus::Voided->value], true)),
                    TextInput::make('sort_order')
                        ->label(__('dberp.fields.sort_order'))
                        ->numeric()
                        ->default(0)
                        ->disabled(fn (): bool => $this->getOwnerRecord()->status !== PurchaseOrderStatus::Draft->value)
                        ->required(),
                    Textarea::make('remark')
                        ->label(__('dberp.fields.remark'))
                        ->rows(2)
                        ->disabled(fn (): bool => $this->getOwnerRecord()->status !== PurchaseOrderStatus::Draft->value)
                        ->columnSpanFull(),
                    Textarea::make('price_hit_summary')
                        ->label(__('dberp.fields.price_hit_summary'))
                        ->disabled()
                        ->dehydrated(false)
                        ->rows(2)
                        ->columnSpanFull(),
                ],
            ));
    }

    public function table(Table $table): Table
    {
        return $table
            ->modifyQueryUsing(fn ($query) => $query->with(array_merge(
                DberpDocumentLineSpecPresentation::eagerLoadsForDocumentLines(['baseUnit', 'auxiliaryUnit']),
                ['requestedWarehouse'],
            )))
            ->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))
                    ->toggleable(isToggledHiddenByDefault: true),
                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('requestedWarehouse.name')
                    ->label(__('dberp.fields.requested_warehouse'))
                    ->placeholder('—')
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('unit_name')
                    ->label(__('dberp.fields.document_line_entered_unit'))
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('quantity')
                    ->label(__('dberp.fields.ordered_quantity'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::quantity($state)),
                TextColumn::make('arrived_quantity')
                    ->label(__('dberp.fields.arrived_quantity'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::quantity($state)),
                TextColumn::make('received_quantity')
                    ->label(__('dberp.fields.received_quantity'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::quantity($state)),
                TextColumn::make('pending_receipt_quantity')
                    ->label(__('dberp.fields.pending_receipt_quantity'))
                    ->state(function (Model $record): string {
                        if (! $record instanceof DberpPurchaseOrderItem) {
                            return DberpNumberFormatter::quantity('0');
                        }

                        return DberpNumberFormatter::quantity(
                            app(PurchaseOrderOverviewService::class)->displayRemainingArrivalQuantity($record),
                        );
                    }),
                TextColumn::make('returned_quantity')
                    ->label(__('dberp.fields.returned_quantity'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::quantity($state)),
                TextColumn::make('execution_status')
                    ->label(__('dberp.fields.execution_status'))
                    ->badge()
                    ->formatStateUsing(fn (?string $state): string => PurchaseOrderItemExecutionStatus::tryFrom((string) $state)?->label()
                        ?? (string) __('dberp.messages.not_available')),
                TextColumn::make('line_amount')
                    ->label(__('dberp.fields.line_amount'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::money($state)),
                TextColumn::make('document_line_primary_base_quantity')
                    ->label(__('dberp.fields.document_line_primary_base_quantity'))
                    ->state(fn ($record): string => DberpDocumentLinePresentation::primaryBaseQuantityDisplay($record))
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('document_line_conversion_snapshot')
                    ->label(__('dberp.fields.document_line_conversion_snapshot'))
                    ->state(fn ($record): string => DberpDocumentLinePresentation::conversionSnapshotLine($record))
                    ->wrap()
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('rejected_quantity')
                    ->label(__('dberp.fields.rejected_quantity'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::quantity($state))
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('external_sku')
                    ->label(__('dberp.fields.external_sku'))
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('expected_arrival_date')
                    ->label(__('dberp.fields.expected_arrival_date'))
                    ->date()
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('last_arrival_date')
                    ->label(__('dberp.fields.last_arrival_date'))
                    ->date()
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('unit_price')
                    ->label(__('dberp.fields.unit_price'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::price($state))
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('matched_reference_price')
                    ->label(__('dberp.fields.matched_reference_price'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::price($state))
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('price_hit_label')
                    ->label(__('dberp.fields.price_hit_label'))
                    ->badge()
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('price_hit_summary')
                    ->label(__('dberp.fields.price_hit_summary'))
                    ->wrap()
                    ->toggleable(isToggledHiddenByDefault: true),
                TextColumn::make('sort_order')
                    ->label(__('dberp.fields.sort_order'))
                    ->toggleable(isToggledHiddenByDefault: true),
            ])
            ->headerActions([
                DberpDocumentLineBulkProductAddHeaderActions::purchaseOrderItems(
                    fn (): Model => $this->getOwnerRecord(),
                ),
                CreateAction::make()
                    ->using(function (array $data): Model {
                        $data = DberpLineProductSkuFormFields::finalizeLineSkuFormData($data);

                        return app(PurchaseOrderService::class)->createItem($this->getOwnerRecord(), $data);
                    })
                    ->visible(fn (): bool => $this->getOwnerRecord()->status === PurchaseOrderStatus::Draft->value),
            ])
            ->recordActions([
                EditAction::make()
                    ->using(function (DberpPurchaseOrderItem $record, array $data): Model {
                        $data = DberpLineProductSkuFormFields::finalizeLineSkuFormData($data);

                        return app(PurchaseOrderService::class)->updateItem($record, $data);
                    })
                    ->visible(fn (): bool => $this->getOwnerRecord()->status === PurchaseOrderStatus::Draft->value),
                DeleteAction::make()
                    ->visible(fn (): bool => $this->getOwnerRecord()->status === PurchaseOrderStatus::Draft->value),
            ]);
    }

    private function orderItemLocksSourceFields(?DberpPurchaseOrderItem $record): bool
    {
        return $record instanceof DberpPurchaseOrderItem
            && ($record->purchase_request_item_id !== null || $record->source_inquiry_quote_id !== null);
    }
}
