<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Filament\Resources\DberpStocktakeOrders\RelationManagers;

use App\Business\Inventory\Enums\InventoryDocumentStatus;
use App\Business\Inventory\Enums\StocktakeResultType;
use App\Business\Inventory\StocktakeOrderService;
use App\Filament\Support\DberpFilamentNumberFields;
use App\Models\DberpProduct;
use App\Models\DberpStocktakeOrder;
use App\Support\DberpDocumentLineBarcodeQuickAddHeaderActions;
use App\Support\DberpDocumentLineInboundSerialNumberFormFields;
use App\Support\DberpDocumentLineInventoryHintFormFields;
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\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.stocktake_items');
    }

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

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

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

        $resolveProduct = DberpDocumentLineUnitFormFields::resolveProductFromProductIdField('product_id');
        $owner = $this->getOwnerRecord();
        $stocktakeOrder = $owner instanceof DberpStocktakeOrder ? ($owner->fresh() ?? $owner) : null;

        return $schema
            ->components(array_merge([
                DberpDocumentLineUnitFormFields::wireProductDriver(
                    $stocktakeOrder instanceof DberpStocktakeOrder
                        ? DberpProductSkuSelectOptions::configureStocktakeOrderItemProductSelect(
                            Select::make('product_id')
                                ->label(__('dberp.fields.product'))
                                ->required(),
                            $stocktakeOrder,
                        )
                        : DberpProductSkuSelectOptions::configureInventoryProductSelect(
                            Select::make('product_id')
                                ->label(__('dberp.fields.product'))
                                ->required(),
                        ),
                    DberpDocumentLineUnitFormFields::resolveProductFromProductIdField('product_id'),
                    function (Set $set, Get $get): void {
                        DberpLineProductSkuFormFields::syncAfterProductIdChanged($set, $get, 'product_id');
                    },
                ),
            ], DberpLineProductSkuFormFields::specificationComboFields('product_id', $locksLine), DberpDocumentLineUnitFormFields::blocks(
                $resolveProduct,
                false,
                $locksLine,
            ), DberpDocumentLineUnitFormFields::withApproxBasePreviewAfterQuantityField([
                DberpDocumentLineInventoryHintFormFields::stocktakeBookQuantityPlaceholder(
                    fn (): int => (int) ($this->getOwnerRecord()->warehouse_id ?? 0),
                ),
                DberpFilamentNumberFields::documentLineQuantityInput(
                    TextInput::make('actual_quantity')
                        ->label(__('dberp.document_line.entry_quantity'))
                        ->required(),
                    withHelperText: false,
                    minValue: 0.0,
                )->helperText(__('dberp.hints.stocktake_actual_quantity')),
                ...DberpDocumentLineInboundSerialNumberFormFields::inboundSerialNumberFields(
                    $resolveProduct,
                    'actual_quantity',
                    'dberp.fields.stocktake_actual_serial_numbers',
                ),
                TextInput::make('sort_order')
                    ->label(__('dberp.fields.sort_order'))
                    ->numeric()
                    ->default(0)
                    ->required(),
                Textarea::make('remark')
                    ->label(__('dberp.fields.remark'))
                    ->rows(2)
                    ->columnSpanFull(),
            ], 'actual_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('book_quantity')
                    ->label(__('dberp.fields.book_quantity'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::quantity($state)),
                TextColumn::make('actual_quantity')
                    ->label(__('dberp.fields.document_line_entered_quantity'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::quantity($state)),
                DberpProductInventoryRefinementFormFields::constrainSerialColumn(
                    TextColumn::make('serial_numbers_count')
                        ->label(__('dberp.fields.stocktake_counted_serial_numbers'))
                        ->state(fn ($record): int => count($record->serial_numbers ?? [])),
                ),
                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),
                TextColumn::make('difference_quantity')
                    ->label(__('dberp.fields.difference_quantity'))
                    ->formatStateUsing(fn ($state): string => DberpNumberFormatter::quantity($state)),
                TextColumn::make('result_type')
                    ->label(__('dberp.fields.result_type'))
                    ->badge()
                    ->formatStateUsing(fn (?string $state): string => StocktakeResultType::tryFrom((string) $state)?->label() ?? (string) $state),
                TextColumn::make('sort_order')
                    ->label(__('dberp.fields.sort_order')),
            ])
            ->headerActions([
                DberpDocumentLineBarcodeQuickAddHeaderActions::stocktakeOrderItems(
                    fn (): Model => $this->getOwnerRecord(),
                ),
                CreateAction::make()
                    ->mutateDataUsing(function (array $data): array {
                        $data = DberpLineProductSkuFormFields::finalizeLineSkuFormData($data);
                        $this->assertStocktakeLineProductWithinScope($data);

                        return $this->enrichDraftStocktakeLineFormData($data);
                    })
                    ->visible(fn (): bool => $this->getOwnerRecord()->status === InventoryDocumentStatus::Draft->value),
            ])
            ->recordActions([
                EditAction::make()
                    ->mutateDataUsing(function (array $data): array {
                        $data = DberpLineProductSkuFormFields::finalizeLineSkuFormData($data);
                        $this->assertStocktakeLineProductWithinScope($data);

                        return $this->enrichDraftStocktakeLineFormData($data);
                    })
                    ->visible(fn (): bool => $this->getOwnerRecord()->status === InventoryDocumentStatus::Draft->value),
                DeleteAction::make()
                    ->visible(fn (): bool => $this->getOwnerRecord()->status === InventoryDocumentStatus::Draft->value),
            ]);
    }

    /**
     * @param  array<string, mixed>  $data
     * @return array<string, mixed>
     */
    private function enrichDraftStocktakeLineFormData(array $data): array
    {
        $owner = $this->getOwnerRecord();
        if (! $owner instanceof DberpStocktakeOrder) {
            return $data;
        }

        return app(StocktakeOrderService::class)->enrichDraftLineFormData($owner->fresh() ?? $owner, $data);
    }

    /**
     * @param  array<string, mixed>  $data
     */
    private function assertStocktakeLineProductWithinScope(array $data): void
    {
        $owner = $this->getOwnerRecord();
        if (! $owner instanceof DberpStocktakeOrder) {
            return;
        }

        $productId = (int) ($data['product_id'] ?? 0);
        if ($productId <= 0) {
            return;
        }

        $product = DberpProduct::query()->find($productId);
        if ($product === null) {
            return;
        }

        $owner->fresh()?->assertLineProductWithinScope($product);
    }
}
