<?php

declare(strict_types=1);

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

namespace App\Support;

use App\Business\Product\DberpProductUnitConversionService;
use App\Models\DberpOtherStockInOrderItem;
use App\Models\DberpOtherStockOutOrderItem;
use App\Models\DberpPurchaseOrderItem;
use App\Models\DberpPurchaseReceiptOrderItem;
use App\Models\DberpPurchaseRequestItem;
use App\Models\DberpPurchaseReturnOrderItem;
use App\Models\DberpSalesOrderItem;
use App\Models\DberpSalesOutboundOrderItem;
use App\Models\DberpSalesQuoteItem;
use App\Models\DberpSalesReturnOrderItem;
use App\Models\DberpStocktakeOrderItem;
use App\Models\DberpTransferOrderItem;
use Illuminate\Database\Eloquent\Model;

/**
 * 单据明细：录入数量/单位、主计量数量、换算关系等界面展示（优先使用行上快照字段）。
 */
final class DberpDocumentLinePresentation
{
    /**
     * @return array{entered: string, base: ?string}
     */
    public static function quantityAttributeKeys(Model $line): array
    {
        return match ($line::class) {
            DberpPurchaseOrderItem::class => ['entered' => 'quantity', 'base' => 'base_quantity'],
            DberpSalesOrderItem::class => ['entered' => 'quantity', 'base' => 'base_quantity'],
            DberpPurchaseReceiptOrderItem::class => ['entered' => 'received_quantity', 'base' => 'base_received_quantity'],
            DberpSalesOutboundOrderItem::class => ['entered' => 'ship_quantity', 'base' => 'base_ship_quantity'],
            DberpPurchaseReturnOrderItem::class,
            DberpSalesReturnOrderItem::class => ['entered' => 'return_quantity', 'base' => 'base_return_quantity'],
            DberpOtherStockInOrderItem::class,
            DberpOtherStockOutOrderItem::class,
            DberpTransferOrderItem::class => ['entered' => 'quantity', 'base' => 'base_quantity'],
            DberpStocktakeOrderItem::class => ['entered' => 'actual_quantity', 'base' => 'base_actual_quantity'],
            DberpPurchaseRequestItem::class => ['entered' => 'request_quantity', 'base' => null],
            DberpSalesQuoteItem::class => ['entered' => 'quantity', 'base' => null],
            default => ['entered' => 'quantity', 'base' => null],
        };
    }

    public static function enteredQuantityDisplay(Model $line): string
    {
        $keys = self::quantityAttributeKeys($line);
        $qty = $line->getAttribute($keys['entered']);
        $qtyString = self::normalizeNumericToDisplayString($qty);
        if ($qtyString === null) {
            return '—';
        }

        $unit = trim((string) ($line->getAttribute('unit_name') ?? ''));

        return $unit === ''
            ? DberpNumberFormatter::quantity($qtyString)
            : DberpNumberFormatter::quantity($qtyString).' '.$unit;
    }

    public static function enteredUnitDisplay(Model $line): string
    {
        $unit = trim((string) ($line->getAttribute('unit_name') ?? ''));

        return $unit !== '' ? $unit : '—';
    }

    public static function primaryBaseQuantityDisplay(Model $line): string
    {
        $keys = self::quantityAttributeKeys($line);
        $baseKey = $keys['base'];
        $enteredKey = $keys['entered'];

        $baseString = null;
        if ($baseKey !== null) {
            $raw = $line->getAttribute($baseKey);
            $baseString = self::normalizeNumericToDisplayString($raw);
        }

        if ($baseString === null || $baseString === '') {
            $baseString = DberpProductUnitConversionService::enteredQuantityToBaseOrZero(
                (string) ($line->getAttribute($enteredKey) ?? '0'),
                (bool) $line->getAttribute('is_auxiliary_unit'),
                $line->getAttribute('auxiliary_unit_quantity'),
                $line->getAttribute('base_unit_quantity'),
            );
        }

        if ($baseString === '' || ! is_numeric((string) $baseString)) {
            $baseString = '0';
        }

        $baseUnitName = '';
        if (method_exists($line, 'baseUnit')) {
            $rel = $line->relationLoaded('baseUnit') ? $line->baseUnit : $line->baseUnit()->first();
            $baseUnitName = trim((string) ($rel?->name ?? ''));
        }

        return $baseUnitName === ''
            ? DberpNumberFormatter::quantity($baseString)
            : DberpNumberFormatter::quantity($baseString).' '.$baseUnitName;
    }

    public static function conversionSnapshotLine(Model $line): string
    {
        if (! (bool) $line->getAttribute('is_auxiliary_unit')) {
            return (string) __('dberp.messages.document_line_no_auxiliary_selected');
        }

        $baseId = (int) ($line->getAttribute('base_unit_id') ?? 0);
        $auxId = (int) ($line->getAttribute('auxiliary_unit_id') ?? 0);
        $text = DberpProductAuxiliaryUnitPreview::fromSnapshot(
            $baseId,
            $auxId,
            $line->getAttribute('auxiliary_unit_quantity'),
            $line->getAttribute('base_unit_quantity'),
        );

        return $text !== '' ? $text : '—';
    }

    public static function receiptBaseArrivalDisplay(Model $line): string
    {
        if (! $line instanceof DberpPurchaseReceiptOrderItem) {
            return '—';
        }

        $raw = $line->getAttribute('base_arrival_quantity');
        $baseString = self::normalizeNumericToDisplayString($raw);
        if ($baseString === null || bccomp($baseString, '0', 6) !== 1) {
            return '—';
        }

        $baseUnitName = '';
        if (method_exists($line, 'baseUnit')) {
            $rel = $line->relationLoaded('baseUnit') ? $line->baseUnit : $line->baseUnit()->first();
            $baseUnitName = trim((string) ($rel?->name ?? ''));
        }

        return $baseUnitName === ''
            ? DberpNumberFormatter::quantity($baseString)
            : DberpNumberFormatter::quantity($baseString).' '.$baseUnitName;
    }

    private static function normalizeNumericToDisplayString(mixed $value): ?string
    {
        if ($value === null || $value === '') {
            return null;
        }

        $string = is_string($value) ? trim($value) : trim((string) $value);
        if ($string === '' || ! is_numeric($string)) {
            return null;
        }

        return $string;
    }
}
