<?php

declare(strict_types=1);

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

namespace App\Support;

use App\Models\DberpProductSku;
use App\Models\DberpPurchaseOrderItem;
use App\Models\DberpPurchaseReceiptOrderItem;
use App\Models\DberpPurchaseRequestItem;
use App\Models\DberpSalesOrderItem;
use App\Models\DberpSalesOutboundOrderItem;
use Closure;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Utilities\Get;
use Filament\Schemas\Components\Utilities\Set;
use Illuminate\Support\Collection;
use Illuminate\Validation\ValidationException;

/**
 * 单据明细行：商品规格组合（product_sku_id）表单联动、快照与保存前校验。
 */
final class DberpLineProductSkuFormFields
{
    /**
     * @return Collection<int, DberpProductSku>
     */
    public static function enabledSkusForProduct(int $productId): Collection
    {
        if ($productId <= 0) {
            return collect();
        }

        return DberpProductSku::query()
            ->with('product')
            ->where('product_id', $productId)
            ->where('is_enabled', true)
            ->orderByDesc('is_default')
            ->orderBy('sort_order')
            ->orderBy('id')
            ->get();
    }

    public static function enabledSkuCountForProduct(int $productId): int
    {
        return self::enabledSkusForProduct($productId)->count();
    }

    /**
     * @return array<int|string, string>
     */
    public static function skuOptionsKeyedById(int $productId): array
    {
        $out = [];
        foreach (self::enabledSkusForProduct($productId) as $sku) {
            if ($sku instanceof DberpProductSku) {
                $out[$sku->getKey()] = self::optionLabelForSku($sku);
            }
        }

        return $out;
    }

    public static function optionLabelForSku(DberpProductSku $sku): string
    {
        $summary = trim((string) ($sku->spec_text ?? ''));
        $code = trim((string) ($sku->sku_code ?? ''));
        $parts = [];
        if ($summary !== '') {
            $parts[] = (string) __('dberp.fields.document_line_spec_summary').'：'.$summary;
        }
        if ($code !== '') {
            $parts[] = (string) __('dberp.fields.document_line_spec_code').'：'.$code;
        }

        return $parts !== [] ? implode(' · ', $parts) : (string) __('dberp.fields.document_line_product_spec_combo');
    }

    public static function requiresExplicitSkuSelection(int $productId): bool
    {
        return self::enabledSkuCountForProduct($productId) > 1;
    }

    /**
     * @param  callable(string, mixed): void  $set
     */
    public static function clearLineSkuState(callable $set): void
    {
        $set('product_sku_id', null);
        $set('product_sku_code', null);
        $set('product_sku_name', null);
        $set('product_sku_spec', null);
    }

    /**
     * @param  callable(string, mixed): void  $set
     */
    public static function applyLineSkuSnapshots(callable $set, ?int $skuId): void
    {
        if ($skuId === null || $skuId <= 0) {
            self::clearLineSkuState($set);

            return;
        }

        $sku = DberpProductSku::query()->with('product')->find($skuId);
        if (! $sku instanceof DberpProductSku) {
            self::clearLineSkuState($set);

            return;
        }

        $set('product_sku_id', $skuId);
        $code = trim((string) ($sku->sku_code ?? ''));
        $set('product_sku_code', $code !== '' ? $code : null);
        $set('product_sku_spec', $sku->spec_text !== null && trim((string) $sku->spec_text) !== '' ? (string) $sku->spec_text : null);
        $productName = trim((string) ($sku->product?->name ?? ''));
        $spec = trim((string) ($sku->spec_text ?? ''));
        $display = trim(implode(' ', array_filter([$productName, $spec !== '' ? $spec : null])));
        $set('product_sku_name', $display !== '' ? mb_substr($display, 0, 160) : null);
    }

    /**
     * 商品变更后：清空原规格，并在「仅一条启用规格组合」时自动带出。
     */
    public static function syncAfterProductIdChanged(Set $set, Get $get, string $productIdField = 'product_id'): void
    {
        self::clearLineSkuState($set);
        $productId = (int) ($get($productIdField) ?? 0);
        if ($productId <= 0) {
            return;
        }

        self::autoFillSingleEnabledSku($set, $productId);
    }

    /**
     * @param  callable(string, mixed): void  $set
     */
    public static function autoFillSingleEnabledSku(callable $set, int $productId): void
    {
        $skus = self::enabledSkusForProduct($productId);
        if ($skus->count() !== 1) {
            return;
        }

        $first = $skus->first();
        if ($first instanceof DberpProductSku) {
            self::applyLineSkuSnapshots($set, (int) $first->getKey());
        }
    }

    public static function applyFromPurchaseRequestItemSelection(Set $set, ?int $purchaseRequestItemId): void
    {
        self::clearLineSkuState($set);
        if ($purchaseRequestItemId === null || $purchaseRequestItemId <= 0) {
            $set('product_id', null);
            DberpDocumentRemarkPropagation::applyLineRemark($set, null);

            return;
        }

        $line = DberpPurchaseRequestItem::query()->with(['productSku', 'product'])->find($purchaseRequestItemId);
        if (! $line instanceof DberpPurchaseRequestItem) {
            $set('product_id', null);
            DberpDocumentRemarkPropagation::applyLineRemark($set, null);

            return;
        }

        $set('product_id', $line->product_id);
        DberpDocumentRemarkPropagation::applyLineRemark($set, $line->remark);
        if ($line->product_sku_id !== null && (int) $line->product_sku_id > 0) {
            self::applyLineSkuSnapshots($set, (int) $line->product_sku_id);

            return;
        }

        self::autoFillSingleEnabledSku($set, (int) $line->product_id);
    }

    public static function applyFromPurchaseOrderItemSelection(Set $set, ?int $purchaseOrderItemId): void
    {
        self::clearLineSkuState($set);
        if ($purchaseOrderItemId === null || $purchaseOrderItemId <= 0) {
            return;
        }

        $line = DberpPurchaseOrderItem::query()->with(['productSku', 'product'])->find($purchaseOrderItemId);
        if (! $line instanceof DberpPurchaseOrderItem) {
            return;
        }

        $set('product_id', $line->product_id);
        DberpDocumentRemarkPropagation::applyLineRemark($set, $line->remark);
        if ($line->product_sku_id !== null && (int) $line->product_sku_id > 0) {
            self::applyLineSkuSnapshots($set, (int) $line->product_sku_id);

            return;
        }

        self::autoFillSingleEnabledSku($set, (int) $line->product_id);
    }

    /**
     * 采购到货明细：引用采购订单行时带出商品、规格、单位、备注、未入库数量与采购单价。
     */
    public static function applyFromPurchaseOrderItemSelectionForReceipt(Set $set, ?int $purchaseOrderItemId): void
    {
        self::applyFromPurchaseOrderItemSelection($set, $purchaseOrderItemId);

        if ($purchaseOrderItemId === null || $purchaseOrderItemId <= 0) {
            $set('arrival_quantity', null);
            $set('received_quantity', null);
            $set('unit_price', null);

            return;
        }

        $line = DberpPurchaseOrderItem::query()->with(['product.unit'])->find($purchaseOrderItemId);
        if (! $line instanceof DberpPurchaseOrderItem) {
            return;
        }

        if ($line->unit_id !== null && (int) $line->unit_id > 0) {
            $set('unit_id', (int) $line->unit_id);
        }

        $defaults = self::receiptQuantityAndPriceDefaultsForPurchaseOrderItem($line);
        $set('arrival_quantity', $defaults['arrival_quantity']);
        $set('received_quantity', $defaults['received_quantity']);
        $set('unit_price', $defaults['unit_price']);
    }

    /**
     * @return array{arrival_quantity: ?string, received_quantity: ?string, unit_price: string}
     */
    public static function receiptQuantityAndPriceDefaultsForPurchaseOrderItem(DberpPurchaseOrderItem $line): array
    {
        $remaining = max(0.0, (float) ($line->remaining_arrival_quantity ?? 0));
        $quantity = $remaining > 0.00005
            ? number_format($remaining, 4, '.', '')
            : null;

        return [
            'arrival_quantity' => $quantity,
            'received_quantity' => $quantity,
            'unit_price' => number_format((float) ($line->unit_price ?? 0), 4, '.', ''),
        ];
    }

    public static function applyFromPurchaseReceiptItemSelection(Set $set, ?int $receiptItemId): void
    {
        self::clearLineSkuState($set);
        if ($receiptItemId === null || $receiptItemId <= 0) {
            return;
        }

        $line = DberpPurchaseReceiptOrderItem::query()->with(['productSku', 'product'])->find($receiptItemId);
        if (! $line instanceof DberpPurchaseReceiptOrderItem) {
            return;
        }

        $set('product_id', $line->product_id);
        DberpDocumentRemarkPropagation::applyLineRemark($set, $line->remark);
        if ($line->product_sku_id !== null && (int) $line->product_sku_id > 0) {
            self::applyLineSkuSnapshots($set, (int) $line->product_sku_id);

            return;
        }

        self::autoFillSingleEnabledSku($set, (int) $line->product_id);
    }

    public static function applyFromSalesOrderItemSelection(Set $set, ?int $salesOrderItemId): void
    {
        self::clearLineSkuState($set);
        if ($salesOrderItemId === null || $salesOrderItemId <= 0) {
            return;
        }

        $line = DberpSalesOrderItem::query()->with(['productSku', 'product'])->find($salesOrderItemId);
        if (! $line instanceof DberpSalesOrderItem) {
            return;
        }

        $set('product_id', $line->product_id);
        DberpDocumentRemarkPropagation::applyLineRemark($set, $line->remark);
        if ($line->product_sku_id !== null && (int) $line->product_sku_id > 0) {
            self::applyLineSkuSnapshots($set, (int) $line->product_sku_id);

            return;
        }

        self::autoFillSingleEnabledSku($set, (int) $line->product_id);
    }

    /**
     * 销售出库明细：引用销售订单行时带出单位、待出库数量与单价。
     */
    public static function applyFromSalesOrderItemSelectionForOutbound(Set $set, ?int $salesOrderItemId): void
    {
        self::applyFromSalesOrderItemSelection($set, $salesOrderItemId);

        if ($salesOrderItemId === null || $salesOrderItemId <= 0) {
            $set('ship_quantity', null);
            $set('unit_price', null);

            return;
        }

        $line = DberpSalesOrderItem::query()->find($salesOrderItemId);
        if (! $line instanceof DberpSalesOrderItem) {
            return;
        }

        if ($line->unit_id !== null && (int) $line->unit_id > 0) {
            $set('unit_id', (int) $line->unit_id);
        }

        $pending = bcsub((string) ($line->quantity ?? '0'), (string) ($line->shipped_quantity ?? '0'), 4);
        if (bccomp($pending, '0', 4) === 1) {
            $set('ship_quantity', $pending);
        } else {
            $set('ship_quantity', null);
        }

        $set('unit_price', (string) ($line->unit_price ?? '0'));

        if ($line->sort_order !== null) {
            $set('sort_order', (int) $line->sort_order);
        }
    }

    public static function applyFromSalesOutboundItemSelection(Set $set, ?int $outboundItemId): void
    {
        self::clearLineSkuState($set);
        if ($outboundItemId === null || $outboundItemId <= 0) {
            return;
        }

        $line = DberpSalesOutboundOrderItem::query()->with(['productSku', 'product'])->find($outboundItemId);
        if (! $line instanceof DberpSalesOutboundOrderItem) {
            return;
        }

        $set('product_id', $line->product_id);
        DberpDocumentRemarkPropagation::applyLineRemark($set, $line->remark);
        if ($line->product_sku_id !== null && (int) $line->product_sku_id > 0) {
            self::applyLineSkuSnapshots($set, (int) $line->product_sku_id);

            return;
        }

        self::autoFillSingleEnabledSku($set, (int) $line->product_id);
    }

    /**
     * @param  Closure|bool  $disabled  为 bool 时表示是否整段锁定；为 Closure 时返回是否禁用。
     * @return list<Select|TextInput>
     */
    public static function specificationComboFields(
        string $productIdField,
        Closure|bool $disabled,
    ): array {
        $isDisabled = $disabled instanceof Closure ? $disabled : fn (): bool => (bool) $disabled;

        $skuSelect = Select::make('product_sku_id')
            ->label(__('dberp.fields.document_line_product_spec_combo'))
            ->options(fn (Get $get): array => self::skuOptionsKeyedById((int) ($get($productIdField) ?? 0)))
            ->searchable(fn (Get $get): bool => self::enabledSkuCountForProduct((int) ($get($productIdField) ?? 0)) >= DberpProductSkuSelectOptions::SEARCHABLE_OPTION_THRESHOLD)
            ->preload()
            ->live()
            ->afterStateUpdated(function (Set $set, mixed $state): void {
                $id = $state === null || $state === '' ? null : (int) $state;
                self::applyLineSkuSnapshots($set, $id > 0 ? $id : null);
            })
            ->required(fn (Get $get): bool => self::requiresExplicitSkuSelection((int) ($get($productIdField) ?? 0)))
            ->disabled(fn (Get $get): bool => $isDisabled() || (int) ($get($productIdField) ?? 0) <= 0);

        return array_merge([
            $skuSelect,
        ], self::readOnlySnapshotFields($isDisabled));
    }

    /**
     * @param  Closure(): bool  $isDisabled
     * @return list<TextInput>
     */
    private static function readOnlySnapshotFields(Closure $isDisabled): array
    {
        return [
            TextInput::make('product_sku_code')
                ->label(__('dberp.fields.document_line_spec_code'))
                ->maxLength(64)
                ->disabled(fn (): bool => $isDisabled())
                ->dehydrated(),
            TextInput::make('product_sku_name')
                ->label(__('dberp.fields.document_line_spec_display_name'))
                ->maxLength(160)
                ->disabled(fn (): bool => $isDisabled())
                ->dehydrated(),
            TextInput::make('product_sku_spec')
                ->label(__('dberp.fields.document_line_spec_summary'))
                ->maxLength(512)
                ->disabled(fn (): bool => $isDisabled())
                ->dehydrated(),
        ];
    }

    /**
     * @param  array<string, mixed>  $data
     * @return array<string, mixed>
     */
    public static function finalizeLineSkuFormData(array $data, string $productIdField = 'product_id'): array
    {
        $pid = (int) ($data[$productIdField] ?? 0);
        $rawSku = $data['product_sku_id'] ?? null;
        $skuId = $rawSku === null || $rawSku === '' ? null : (int) $rawSku;

        if ($pid > 0 && $skuId === null && self::enabledSkuCountForProduct($pid) === 1) {
            $only = self::enabledSkusForProduct($pid)->first();
            if ($only instanceof DberpProductSku) {
                $skuId = (int) $only->getKey();
            }
        }

        $data['product_sku_id'] = $skuId;

        self::assertLineSkuAgainstProduct($data, $productIdField);
        self::enrichSnapshotColumnsFromSkuRow($data, $skuId);

        return $data;
    }

    /**
     * @param  array<string, mixed>  $data
     */
    public static function assertLineSkuAgainstProduct(array $data, string $productIdField = 'product_id'): void
    {
        $pid = (int) ($data[$productIdField] ?? 0);
        $skuId = isset($data['product_sku_id']) && $data['product_sku_id'] !== '' && $data['product_sku_id'] !== null
            ? (int) $data['product_sku_id']
            : null;

        if ($pid <= 0) {
            return;
        }

        $count = self::enabledSkuCountForProduct($pid);
        if ($count > 1 && $skuId === null) {
            throw ValidationException::withMessages([
                'product_sku_id' => (string) __('dberp.errors.line_product_sku_required_when_multi_spec'),
            ]);
        }

        if ($skuId !== null) {
            $ok = DberpProductSku::query()
                ->whereKey($skuId)
                ->where('product_id', $pid)
                ->where('is_enabled', true)
                ->exists();
            if (! $ok) {
                throw ValidationException::withMessages([
                    'product_sku_id' => (string) __('dberp.errors.line_product_sku_must_belong_to_product'),
                ]);
            }
        }
    }

    /**
     * @return array{product_sku_code: string|null, product_sku_name: string|null, product_sku_spec: string|null}
     */
    public static function snapshotTripleForSku(DberpProductSku $sku): array
    {
        $sku->loadMissing('product');

        $code = trim((string) ($sku->sku_code ?? ''));
        $productSkuCode = $code !== '' ? $code : null;
        $productSkuSpec = $sku->spec_text !== null && trim((string) $sku->spec_text) !== '' ? (string) $sku->spec_text : null;
        $productName = trim((string) ($sku->product?->name ?? ''));
        $spec = trim((string) ($sku->spec_text ?? ''));
        $display = trim(implode(' ', array_filter([$productName, $spec !== '' ? $spec : null])));
        $productSkuName = $display !== '' ? mb_substr($display, 0, 160) : null;

        return [
            'product_sku_code' => $productSkuCode,
            'product_sku_name' => $productSkuName,
            'product_sku_spec' => $productSkuSpec,
        ];
    }

    /**
     * @param  array<string, mixed>  $data
     */
    private static function enrichSnapshotColumnsFromSkuRow(array &$data, ?int $skuId): void
    {
        if ($skuId === null || $skuId <= 0) {
            $data['product_sku_code'] = null;
            $data['product_sku_name'] = null;
            $data['product_sku_spec'] = null;

            return;
        }

        $sku = DberpProductSku::query()->with('product')->find($skuId);
        if (! $sku instanceof DberpProductSku) {
            return;
        }

        $triple = self::snapshotTripleForSku($sku);
        $data['product_sku_code'] = $triple['product_sku_code'];
        $data['product_sku_name'] = $triple['product_sku_name'];
        $data['product_sku_spec'] = $triple['product_sku_spec'];
    }
}
