<?php

declare(strict_types=1);

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

namespace App\Business\Settlement;

use App\Support\DberpNumberFormatter;
use App\Tools\Entity\EntityReference;
use App\Tools\Entity\EntityType;
use App\Tools\Support\ToolBusinessDate;
use App\Tools\Support\ToolCurrency;
use App\Tools\Support\ToolDateRange;
use App\Tools\Support\ToolPagedQuery;
use App\Tools\ToolExecutionContext;

/**
 * 账龄分析只读适配。分桶公式全部沿用 SettlementAgingAnalysisService，不在 Tool 层重算。
 */
final class SettlementAgingReadQuery
{
    public function __construct(
        private readonly SettlementAgingAnalysisService $agingAnalysisService,
    ) {}

    /**
     * @param  array<string, mixed>  $input
     * @return array<string, mixed>
     */
    public function analyze(ToolExecutionContext $context, array $input): array
    {
        $asOf = isset($input['as_of_date']) && trim((string) $input['as_of_date']) !== ''
            ? ToolBusinessDate::parse((string) $input['as_of_date'], 'as_of_date')
            : ToolBusinessDate::today($context->timezone);

        // as_of_date 为单日，不构成区间；调用 parseOptional 仅复用格式校验入口。
        ToolDateRange::parseOptional($asOf, $asOf, 'as_of_date', 'as_of_date');

        $normalized = $this->agingAnalysisService->normalizeFilters([
            ...$input,
            'as_of_date' => $asOf,
        ]);

        $page = max(1, (int) ($input['page'] ?? 1));
        $perPage = max(1, (int) ($input['per_page'] ?? 20));

        $analysis = $this->agingAnalysisService->analyze($normalized, [
            'page' => $page,
            'per_page' => $perPage,
        ]);

        return [
            'settlement_side' => $normalized['settlement_side'],
            'as_of_date' => $normalized['as_of_date'],
            'as_of_timezone' => ToolBusinessDate::timezoneFromContext($context),
            'currency' => ToolCurrency::metadata($context),
            'totals' => $this->mapBucketAmounts($analysis['totals']),
            'counterparties' => array_map(
                function (array $row) use ($normalized): array {
                    $type = ($normalized['settlement_side'] ?? '') === 'payable'
                        ? EntityType::Supplier
                        : EntityType::Customer;

                    return EntityReference::attach([
                        'counterparty_id' => (int) $row['counterparty_id'],
                        'counterparty_name' => (string) $row['counterparty_name'],
                        'record_count' => (int) $row['record_count'],
                        ...$this->mapBucketAmounts($row),
                    ], $type, $row['counterparty_id'], null, (string) $row['counterparty_name']);
                },
                $analysis['rows'],
            ),
            'page' => $analysis['page'],
            'per_page' => $analysis['per_page'],
            'total' => $analysis['total_counterparties'],
            'has_more' => ToolPagedQuery::hasMore(
                (int) $analysis['page'],
                (int) $analysis['per_page'],
                (int) $analysis['total_counterparties'],
            ),
        ];
    }

    /**
     * @param  array<string, mixed>  $source
     * @return array<string, string>
     */
    private function mapBucketAmounts(array $source): array
    {
        return [
            'current_amount' => DberpNumberFormatter::money($source['current_amount'] ?? 0),
            'bucket_1_30_amount' => DberpNumberFormatter::money($source['bucket_1_30_amount'] ?? 0),
            'bucket_31_60_amount' => DberpNumberFormatter::money($source['bucket_31_60_amount'] ?? 0),
            'bucket_61_90_amount' => DberpNumberFormatter::money($source['bucket_61_90_amount'] ?? 0),
            'bucket_91_plus_amount' => DberpNumberFormatter::money($source['bucket_91_plus_amount'] ?? 0),
            'total_amount' => DberpNumberFormatter::money($source['total_amount'] ?? 0),
        ];
    }
}
