<?php

declare(strict_types=1);

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

namespace App\Business\Sales;

use App\Models\DberpSalesOrder;
use App\Models\DberpSalesOrderItem;
use App\Support\DberpNumberFormatter;
use App\Tools\Entity\EntityReference;
use App\Tools\Entity\EntityType;
use App\Tools\Exceptions\ToolResourceNotFoundException;
use App\Tools\Support\ToolUniqueRecordLookup;

/**
 * 销售订单只读详情。不复用 SalesOrderOverviewService，避免把 Filament / 插件 UI 字段带进 Tool。
 */
final class SalesOrderReadQuery
{
    /**
     * @param  array<string, mixed>  $input
     * @return array<string, mixed>
     */
    public function find(array $input): array
    {
        $order = ToolUniqueRecordLookup::findOne(
            DberpSalesOrder::query()->with(['customer', 'items']),
            $input,
        );

        if (! $order instanceof DberpSalesOrder) {
            throw ToolResourceNotFoundException::forLookup();
        }

        return $this->mapOrder($order);
    }

    /**
     * @return array<string, mixed>
     */
    private function mapOrder(DberpSalesOrder $order): array
    {
        $customer = $order->customer;

        $items = $order->items
            ->sortBy([
                ['sort_order', 'asc'],
                ['id', 'asc'],
            ])
            ->map(fn (DberpSalesOrderItem $item): array => $this->mapItem($item))
            ->values()
            ->all();

        $customerPayload = [
            'id' => $customer === null ? null : (int) $customer->getKey(),
            'code' => $this->nullableString($customer?->code),
            'name' => (string) ($customer?->name ?? ''),
        ];

        return EntityReference::attach([
            'id' => (int) $order->getKey(),
            'code' => (string) $order->code,
            'status' => (string) $order->status,
            'business_time' => $order->business_time?->toIso8601String(),
            'due_date' => $order->due_date?->toDateString(),
            'handler_employee_id' => $order->handler_employee_id === null ? null : (int) $order->handler_employee_id,
            'customer' => EntityReference::attachNested($customerPayload, EntityType::Customer),
            'amounts' => [
                'total_quantity' => DberpNumberFormatter::quantity($order->total_quantity),
                'total_amount' => DberpNumberFormatter::money($order->total_amount),
                'discount_amount' => DberpNumberFormatter::money($order->discount_amount),
                'final_amount' => DberpNumberFormatter::money($order->final_amount),
                'receivable_amount' => DberpNumberFormatter::money($order->receivable_amount),
                'received_amount' => DberpNumberFormatter::money($order->received_amount),
                'unreceived_amount' => DberpNumberFormatter::money($order->unreceived_amount),
            ],
            'items' => $items,
        ], EntityType::SalesOrder, (int) $order->getKey(), (string) $order->code);
    }

    /**
     * @return array<string, mixed>
     */
    private function mapItem(DberpSalesOrderItem $item): array
    {
        return EntityReference::attach([
            'id' => (int) $item->getKey(),
            'product_id' => (int) $item->product_id,
            'product_code' => (string) $item->product_code,
            'product_name' => (string) $item->product_name,
            'product_sku_id' => $item->product_sku_id === null ? null : (int) $item->product_sku_id,
            'sku_code' => $this->nullableString($item->sku_code),
            'spec_text' => $this->nullableString($item->spec_text),
            'unit_name' => $this->nullableString($item->unit_name),
            'quantity' => DberpNumberFormatter::quantity($item->quantity),
            'unit_price' => DberpNumberFormatter::price($item->unit_price),
            'line_amount' => DberpNumberFormatter::money($item->line_amount),
            'discount_amount' => DberpNumberFormatter::money($item->discount_amount),
            'final_amount' => DberpNumberFormatter::money($item->final_amount),
            'shipped_quantity' => DberpNumberFormatter::quantity($item->shipped_quantity),
            'returned_quantity' => DberpNumberFormatter::quantity($item->returned_quantity),
            'sort_order' => (int) ($item->sort_order ?? 0),
        ], EntityType::Product, (int) $item->product_id, (string) $item->product_code, (string) $item->product_name);
    }

    private function nullableString(mixed $value): ?string
    {
        if ($value === null) {
            return null;
        }

        $normalized = trim((string) $value);

        return $normalized === '' ? null : $normalized;
    }
}
