<?php

declare(strict_types=1);

namespace App\Support;

use App\Business\Product\DberpDocumentLineUnitService;
use App\Models\DberpProduct;
use App\Models\DberpProductSku;
use App\Models\DberpPurchaseOrderItem;
use App\Models\DberpSalesOrderItem;
use Closure;
use Filament\Forms\Components\Component;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Schemas\Components\Utilities\Set;

/**
 * 单据明细「单位 / 换算参考」表单片段（Filament）。
 */
final class DberpDocumentLineUnitFormFields
{
    /**
     * @return list<Placeholder|Select>
     */
    public static function blocks(
        Closure $resolveProduct,
        bool $restrictToBaseInventoryUnit,
        Closure|bool $disabled,
    ): array {
        $isDisabled = $disabled instanceof Closure ? $disabled : fn (): bool => (bool) $disabled;

        return [
            Select::make('unit_id')
                ->label(__('dberp.document_line.unit'))
                ->options(function (Get $get) use ($resolveProduct, $restrictToBaseInventoryUnit): array {
                    $product = $resolveProduct($get);
                    if (! $product instanceof DberpProduct) {
                        return [];
                    }

                    return DberpDocumentLineUnitService::unitOptionsForProduct($product, $restrictToBaseInventoryUnit);
                })
                ->default(function (Get $get) use ($resolveProduct): ?int {
                    $product = $resolveProduct($get);
                    if (! $product instanceof DberpProduct) {
                        return null;
                    }

                    return DberpDocumentLineUnitService::defaultUnitIdForProduct($product);
                })
                ->live()
                ->required()
                ->disabled(function (Get $get) use ($isDisabled, $resolveProduct): bool {
                    if ($isDisabled()) {
                        return true;
                    }

                    return ! $resolveProduct($get) instanceof DberpProduct;
                }),
            Placeholder::make('_document_line_inventory_unit_hint')
                ->label('')
                ->content(fn (): string => $restrictToBaseInventoryUnit ? (string) __('dberp.hints.document_line_unit_inventory_base_only') : '')
                ->visible(fn (): bool => $restrictToBaseInventoryUnit)
                ->columnSpanFull(),
            Placeholder::make('_document_line_conversion_hint')
                ->label(__('dberp.document_line.conversion_relationship'))
                ->content(function (Get $get) use ($resolveProduct): string {
                    $product = $resolveProduct($get);
                    if (! $product instanceof DberpProduct) {
                        return '';
                    }

                    return DberpDocumentLineUnitService::conversionHintForProduct($product);
                })
                ->visible(function (Get $get) use ($resolveProduct): bool {
                    $product = $resolveProduct($get);
                    if (! $product instanceof DberpProduct) {
                        return false;
                    }

                    return trim(DberpDocumentLineUnitService::conversionHintForProduct($product)) !== '';
                })
                ->columnSpanFull(),
        ];
    }

    /**
     * 将「主单位约算」预览插入到录入数量字段之后，避免预览标签出现在数量输入框上方造成误解。
     *
     * @param  array<int|string, Component>  $components
     * @return list<Component>
     */
    public static function withApproxBasePreviewAfterQuantityField(
        array $components,
        string $quantityField,
        Closure $resolveProduct,
    ): array {
        $result = [];

        foreach ($components as $key => $component) {
            $result[$key] = $component;

            if ($component instanceof TextInput && $component->getName() === $quantityField) {
                $result['_document_line_base_qty_preview'] = self::approxBaseQuantityPreviewPlaceholder(
                    $quantityField,
                    $resolveProduct,
                );
            }
        }

        return array_values($result);
    }

    public static function approxBaseQuantityPreviewPlaceholder(
        string $quantityField,
        Closure $resolveProduct,
    ): Placeholder {
        return Placeholder::make('_document_line_base_qty_preview')
            ->label(__('dberp.document_line.approx_base_preview'))
            ->content(function (Get $get) use ($resolveProduct, $quantityField): string {
                $product = $resolveProduct($get);
                if (! $product instanceof DberpProduct) {
                    return '';
                }

                $preview = DberpDocumentLineUnitService::approximateBaseQuantityPreview(
                    $get($quantityField),
                    (int) ($get('unit_id') ?? 0),
                    $product,
                );

                return $preview ?? '';
            })
            ->visible(function (Get $get) use ($resolveProduct, $quantityField): bool {
                $product = $resolveProduct($get);
                if (! $product instanceof DberpProduct) {
                    return false;
                }

                return DberpDocumentLineUnitService::approximateBaseQuantityPreview(
                    $get($quantityField),
                    (int) ($get('unit_id') ?? 0),
                    $product,
                ) !== null;
            })
            ->columnSpanFull();
    }

    public static function ownerStatusLocksDocumentLineFields(?string $status, string $draftStatusValue): bool
    {
        if ($status === null || $status === '') {
            return false;
        }

        return $status !== $draftStatusValue;
    }

    /**
     * 商品/规格驱动字段变更时联动刷新单位选项与默认值（须配合 {@see blocks()} 使用）。
     */
    public static function wireProductDriver(Select $field, Closure $resolveProduct, ?Closure $afterProductChanged = null): Select
    {
        return $field
            ->live()
            ->afterStateUpdated(function (Set $set, Get $get) use ($resolveProduct, $afterProductChanged): void {
                self::syncUnitIdFromResolvedProduct($set, $get, $resolveProduct);
                if ($afterProductChanged !== null) {
                    $afterProductChanged($set, $get);
                }
            });
    }

    /**
     * @param  callable(string, mixed): mixed  $set  Filament `Set` 或兼容的 state setter（非 `Closure` 类型）
     */
    public static function resetUnitId(callable $set): void
    {
        $set('unit_id', null);
    }

    public static function syncUnitIdFromResolvedProduct(Set $set, Get $get, Closure $resolveProduct): void
    {
        $product = $resolveProduct($get);
        if (! $product instanceof DberpProduct) {
            self::resetUnitId($set);

            return;
        }

        $set('unit_id', DberpDocumentLineUnitService::defaultUnitIdForProduct($product));
    }

    /**
     * @return Closure(Get): (?DberpProduct)
     */
    public static function resolveProductFromSkuField(string $skuField): Closure
    {
        return function (Get $get) use ($skuField): ?DberpProduct {
            $skuId = (int) ($get($skuField) ?? 0);
            if ($skuId <= 0) {
                return null;
            }

            $sku = DberpProductSku::query()
                ->with(['product.unit', 'product.auxiliaryUnit'])
                ->find($skuId);

            return $sku?->product;
        };
    }

    /**
     * @return Closure(Get): (?DberpProduct)
     */
    public static function resolveProductFromProductIdField(string $productField): Closure
    {
        return function (Get $get) use ($productField): ?DberpProduct {
            $productId = (int) ($get($productField) ?? 0);
            if ($productId <= 0) {
                return null;
            }

            return DberpProduct::query()
                ->with(['unit', 'auxiliaryUnit'])
                ->find($productId);
        };
    }

    /**
     * @return Closure(Get): (?DberpProduct)
     */
    public static function resolveProductFromPurchaseOrderItemField(string $purchaseOrderItemField): Closure
    {
        return function (Get $get) use ($purchaseOrderItemField): ?DberpProduct {
            $id = (int) ($get($purchaseOrderItemField) ?? 0);
            if ($id <= 0) {
                return null;
            }

            $line = DberpPurchaseOrderItem::query()
                ->with(['product.unit', 'product.auxiliaryUnit'])
                ->find($id);

            return $line?->product;
        };
    }

    /**
     * @return Closure(Get): (?DberpProduct)
     */
    public static function resolveProductFromSalesOrderItemField(string $salesOrderItemField): Closure
    {
        return function (Get $get) use ($salesOrderItemField): ?DberpProduct {
            $id = (int) ($get($salesOrderItemField) ?? 0);
            if ($id <= 0) {
                return null;
            }

            $line = DberpSalesOrderItem::query()
                ->with(['product.unit', 'product.auxiliaryUnit'])
                ->find($id);

            return $line?->product;
        };
    }
}
