<?php

declare(strict_types=1);

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

namespace App\Tools\MasterData;

use App\Business\MasterData\CustomerExposureSearchQuery;
use App\Business\MasterData\SupplierExposureSearchQuery;
use App\Tools\Entity\EntityReferenceSchema;
use App\Tools\Support\ToolDateSchema;
use App\Tools\Support\ToolListSchema;

/**
 * 客户/供应商跨域暴露检索 JSON Schema。
 */
final class PartnerExposureToolSchema
{
    /**
     * @return array<string, mixed>
     */
    public static function customerInput(): array
    {
        return [
            'type' => 'object',
            'additionalProperties' => false,
            'properties' => [
                'q' => [
                    'type' => 'string',
                    'minLength' => 1,
                    'maxLength' => 100,
                ],
                'customer_id' => ['type' => 'integer', 'minimum' => 1],
                'is_enabled' => ['type' => 'boolean'],
                'date_from' => ToolDateSchema::dateProperty('Inclusive sales business calendar date Y-m-d.'),
                'date_until' => ToolDateSchema::dateProperty('Inclusive sales business calendar date Y-m-d.'),
                'period_preset' => ToolDateSchema::periodPresetProperty(),
                ...self::thresholdProperties([
                    'sales_amount_min',
                    'sales_amount_max',
                    'sales_order_count_min',
                    'sales_order_count_max',
                    'outstanding_amount_min',
                    'outstanding_amount_max',
                    'overdue_amount_min',
                    'overdue_amount_max',
                    'open_order_count_min',
                    'open_order_count_max',
                    'open_order_amount_min',
                    'open_order_amount_max',
                ]),
                ...ToolListSchema::paginationInputProperties(
                    CustomerExposureSearchQuery::SORTABLE,
                    CustomerExposureSearchQuery::DEFAULT_SORT,
                ),
            ],
        ];
    }

    /**
     * @return array<string, mixed>
     */
    public static function supplierInput(): array
    {
        return [
            'type' => 'object',
            'additionalProperties' => false,
            'properties' => [
                'q' => [
                    'type' => 'string',
                    'minLength' => 1,
                    'maxLength' => 100,
                ],
                'supplier_id' => ['type' => 'integer', 'minimum' => 1],
                'is_enabled' => ['type' => 'boolean'],
                'date_from' => ToolDateSchema::dateProperty('Inclusive purchase business calendar date Y-m-d.'),
                'date_until' => ToolDateSchema::dateProperty('Inclusive purchase business calendar date Y-m-d.'),
                'period_preset' => ToolDateSchema::periodPresetProperty(),
                ...self::thresholdProperties([
                    'purchase_amount_min',
                    'purchase_amount_max',
                    'purchase_order_count_min',
                    'purchase_order_count_max',
                    'outstanding_amount_min',
                    'outstanding_amount_max',
                    'overdue_amount_min',
                    'overdue_amount_max',
                    'open_order_count_min',
                    'open_order_count_max',
                    'open_order_amount_min',
                    'open_order_amount_max',
                ]),
                ...ToolListSchema::paginationInputProperties(
                    SupplierExposureSearchQuery::SORTABLE,
                    SupplierExposureSearchQuery::DEFAULT_SORT,
                ),
            ],
        ];
    }

    /**
     * @return array<string, mixed>
     */
    public static function customerOutput(): array
    {
        return self::listOutput(self::customerItem());
    }

    /**
     * @return array<string, mixed>
     */
    public static function supplierOutput(): array
    {
        return self::listOutput(self::supplierItem());
    }

    /**
     * @param  list<string>  $fields
     * @return array<string, mixed>
     */
    private static function thresholdProperties(array $fields): array
    {
        $properties = [];
        foreach ($fields as $field) {
            $properties[$field] = [
                'type' => 'number',
                'minimum' => 0,
            ];
        }

        return $properties;
    }

    /**
     * @param  array<string, mixed>  $item
     * @return array<string, mixed>
     */
    private static function listOutput(array $item): array
    {
        $schema = ToolListSchema::paginatedOutputSchemaWithCurrency($item);
        $schema['required'][] = 'as_of_date';
        $schema['required'][] = 'period';
        $schema['properties']['as_of_date'] = ['type' => 'string'];
        $schema['properties']['period'] = [
            'type' => 'object',
            'required' => ['from', 'until'],
            'additionalProperties' => false,
            'properties' => [
                'from' => ['type' => ['string', 'null']],
                'until' => ['type' => ['string', 'null']],
            ],
        ];

        return $schema;
    }

    /**
     * @return array<string, mixed>
     */
    private static function activityTotals(string $amountKey): array
    {
        return [
            'type' => 'object',
            'required' => ['order_count', $amountKey, 'total_quantity'],
            'additionalProperties' => false,
            'properties' => [
                'order_count' => ['type' => 'integer'],
                $amountKey => ['type' => 'string'],
                'total_quantity' => ['type' => 'string'],
            ],
        ];
    }

    /**
     * @return array<string, mixed>
     */
    private static function customerItem(): array
    {
        return [
            'type' => 'object',
            'required' => [
                'id',
                'code',
                'name',
                'is_enabled',
                'sales',
                'outstanding_receivables',
                'overdue_receivables',
                'open_orders',
            ],
            'additionalProperties' => false,
            'properties' => [
                'id' => ['type' => 'integer'],
                'code' => ['type' => 'string'],
                'name' => ['type' => 'string'],
                'is_enabled' => ['type' => 'boolean'],
                'sales' => self::activityTotals('final_amount'),
                'outstanding_receivables' => PartnerToolSchema::countAmount(),
                'overdue_receivables' => PartnerToolSchema::countAmount(),
                'open_orders' => PartnerToolSchema::countAmount(),
                'entity_ref' => EntityReferenceSchema::object(),
            ],
        ];
    }

    /**
     * @return array<string, mixed>
     */
    private static function supplierItem(): array
    {
        return [
            'type' => 'object',
            'required' => [
                'id',
                'code',
                'name',
                'is_enabled',
                'purchases',
                'outstanding_payables',
                'overdue_payables',
                'open_orders',
            ],
            'additionalProperties' => false,
            'properties' => [
                'id' => ['type' => 'integer'],
                'code' => ['type' => 'string'],
                'name' => ['type' => 'string'],
                'is_enabled' => ['type' => 'boolean'],
                'purchases' => self::activityTotals('total_amount'),
                'outstanding_payables' => PartnerToolSchema::countAmount(),
                'overdue_payables' => PartnerToolSchema::countAmount(),
                'open_orders' => PartnerToolSchema::countAmount(),
                'entity_ref' => EntityReferenceSchema::object(),
            ],
        ];
    }
}
