<?php

declare(strict_types=1);

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

namespace App\Business\Settlement;

use App\Business\Settlement\Enums\SettlementOverdueStatus;
use App\Models\DberpPayableRecord;
use App\Models\DberpReceivableRecord;
use App\Support\DberpNumberFormatter;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

/**
 * 往来对象未结/逾期金额聚合。规则与 receivable.search / payable.search 的 overdue_status 相同。
 */
final class PartnerSettlementSnapshotQuery
{
    /**
     * @return array{count: int, amount: string}
     */
    public function receivableOpen(int $customerId): array
    {
        return $this->metric(
            DberpReceivableRecord::query()->where('customer_id', $customerId),
            null,
            '',
        );
    }

    /**
     * @return array{count: int, amount: string}
     */
    public function receivableOverdue(int $customerId, string $asOfDate): array
    {
        return $this->metric(
            DberpReceivableRecord::query()->where('customer_id', $customerId),
            SettlementOverdueStatus::Overdue,
            $asOfDate,
        );
    }

    /**
     * @return array{count: int, amount: string}
     */
    public function payableOpen(int $supplierId): array
    {
        return $this->metric(
            DberpPayableRecord::query()->where('supplier_id', $supplierId),
            null,
            '',
        );
    }

    /**
     * @return array{count: int, amount: string}
     */
    public function payableOverdue(int $supplierId, string $asOfDate): array
    {
        return $this->metric(
            DberpPayableRecord::query()->where('supplier_id', $supplierId),
            SettlementOverdueStatus::Overdue,
            $asOfDate,
        );
    }

    /**
     * @param  Builder<Model>  $query
     * @return array{count: int, amount: string}
     */
    private function metric(Builder $query, ?SettlementOverdueStatus $status, string $asOfDate): array
    {
        if ($status instanceof SettlementOverdueStatus) {
            SettlementDueConstraint::apply($query, $status, $asOfDate);
        } else {
            SettlementDueConstraint::applyOpen($query);
        }

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