<?php

declare(strict_types=1);

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

namespace App\Business\MasterData;

use App\Business\Report\SalesAnalysisReportService;
use App\Business\Sales\Enums\SalesOrderFulfillmentStatus;
use App\Business\Sales\Enums\SalesOrderStatus;
use App\Business\Settlement\PartnerSettlementSnapshotQuery;
use App\Models\DberpCustomer;
use App\Models\DberpSalesOrder;
use App\Support\DberpNumberFormatter;
use App\Tools\Entity\EntityType;
use App\Tools\Exceptions\ToolResourceNotFoundException;
use App\Tools\Support\ToolUniqueRecordLookup;

/**
 * 客户只读经营快照。销售口径复用销售分析报表，未结/逾期复用应收 overdue_status，
 * 未完成订单复用 sales.order.search 的 fulfillment_status=open。不走 Filament 全景服务。
 */
final class CustomerBusinessSummaryQuery
{
    public function __construct(
        private readonly SalesAnalysisReportService $salesAnalysisReportService,
        private readonly PartnerSettlementSnapshotQuery $settlementSnapshotQuery,
    ) {}

    /**
     * @param  array<string, mixed>  $input
     * @param  array{code: string, meaning: string}  $currency
     * @return array<string, mixed>
     */
    public function summarize(array $input, string $asOfDate, array $currency): array
    {
        $period = PartnerBusinessSummarySupport::resolvePeriod($input, $asOfDate);
        $customer = ToolUniqueRecordLookup::findOne(DberpCustomer::query(), $input);

        if (! $customer instanceof DberpCustomer) {
            throw ToolResourceNotFoundException::forLookup();
        }

        $customerId = (int) $customer->getKey();

        return [
            'customer' => PartnerBusinessSummarySupport::identity(
                $customerId,
                (string) $customer->code,
                (string) $customer->name,
                (bool) $customer->is_enabled,
                EntityType::Customer,
            ),
            'as_of_date' => $asOfDate,
            'sales' => $this->salesTotals(['customer_id' => $customerId]),
            'recent_sales' => [
                'period' => [
                    'from' => $period['from'],
                    'until' => $period['until'],
                ],
                ...$this->salesTotals([
                    'customer_id' => $customerId,
                    'business_time_from' => $period['from'],
                    'business_time_until' => $period['until'],
                ]),
            ],
            'open_orders' => $this->openOrders($customerId),
            'outstanding_receivables' => $this->settlementSnapshotQuery->receivableOpen($customerId),
            'overdue_receivables' => $this->settlementSnapshotQuery->receivableOverdue($customerId, $asOfDate),
            'last_business_date' => $this->lastBusinessDate($customerId),
            'currency' => $currency,
        ];
    }

    /**
     * @param  array<string, mixed>  $filters
     * @return array{
     *     order_count: int,
     *     final_amount: string,
     *     receivable_amount: string,
     *     received_amount: string,
     *     unreceived_amount: string,
     *     total_quantity: string
     * }
     */
    private function salesTotals(array $filters): array
    {
        $summary = $this->salesAnalysisReportService->summary(
            $this->salesAnalysisReportService->normalizeFilters($filters),
        );

        return [
            'order_count' => (int) $summary['order_count'],
            'final_amount' => (string) $summary['final_amount'],
            'receivable_amount' => (string) $summary['receivable_amount'],
            'received_amount' => (string) $summary['received_amount'],
            'unreceived_amount' => (string) $summary['unreceived_amount'],
            'total_quantity' => (string) $summary['total_quantity'],
        ];
    }

    /**
     * @return array{count: int, amount: string}
     */
    private function openOrders(int $customerId): array
    {
        $query = DberpSalesOrder::query()
            ->where('customer_id', $customerId)
            ->whereIn('status', SalesOrderFulfillmentStatus::Open->statusValues());

        return [
            'count' => (int) (clone $query)->count(),
            'amount' => DberpNumberFormatter::money((clone $query)->sum('final_amount')),
        ];
    }

    private function lastBusinessDate(int $customerId): ?string
    {
        $latest = DberpSalesOrder::query()
            ->where('customer_id', $customerId)
            ->whereIn('status', SalesOrderStatus::statisticsScopeValues())
            ->max('business_time');

        return PartnerBusinessSummarySupport::calendarDate($latest);
    }
}
