<?php

declare(strict_types=1);

namespace App\Business\Settlement;

use App\Models\DberpPurchaseOrder;
use App\Models\DberpSalesOrder;
use App\Support\DberpDocumentRemarkPropagation;
use App\Support\DberpNumberFormatter;

final class SettlementReceiptPaymentReferenceDefaultsResolver
{
    public function __construct(
        private readonly PayableService $payableService,
        private readonly ReceivableService $receivableService,
    ) {}

    /**
     * @return array<string, int|null>
     */
    public function resolveFromPurchaseOrder(DberpPurchaseOrder $order): array
    {
        return [
            'supplier_id' => (int) $order->supplier_id,
            'handler_employee_id' => $order->handler_employee_id !== null ? (int) $order->handler_employee_id : null,
            'remark' => DberpDocumentRemarkPropagation::trimmedOrNull($order->remark),
        ];
    }

    /**
     * @return array<string, int|null>
     */
    public function resolveFromSalesOrder(DberpSalesOrder $order): array
    {
        return [
            'customer_id' => (int) $order->customer_id,
            'handler_employee_id' => $order->handler_employee_id !== null ? (int) $order->handler_employee_id : null,
            'remark' => DberpDocumentRemarkPropagation::trimmedOrNull($order->remark),
        ];
    }

    /**
     * @return array{payable_amount: string, paid_amount: string, unpaid_amount: string}|null
     */
    public function purchaseOrderSettlementAmounts(?int $purchaseOrderId): ?array
    {
        if ($purchaseOrderId === null || $purchaseOrderId <= 0) {
            return null;
        }

        $order = DberpPurchaseOrder::query()->find($purchaseOrderId);

        if (! $order instanceof DberpPurchaseOrder) {
            return null;
        }

        return [
            'payable_amount' => $this->formatAmount((string) $order->payable_amount),
            'paid_amount' => $this->formatAmount((string) $order->paid_amount),
            'unpaid_amount' => $this->payableService->remainingAmount($order),
        ];
    }

    /**
     * @return array{receivable_amount: string, received_amount: string, unreceived_amount: string}|null
     */
    public function salesOrderSettlementAmounts(?int $salesOrderId): ?array
    {
        if ($salesOrderId === null || $salesOrderId <= 0) {
            return null;
        }

        $order = DberpSalesOrder::query()->find($salesOrderId);

        if (! $order instanceof DberpSalesOrder) {
            return null;
        }

        return [
            'receivable_amount' => $this->formatAmount((string) $order->receivable_amount),
            'received_amount' => $this->formatAmount((string) $order->received_amount),
            'unreceived_amount' => $this->receivableService->remainingAmount($order),
        ];
    }

    public function formatPurchaseOrderSettlementSummary(?int $purchaseOrderId): string
    {
        $amounts = $this->purchaseOrderSettlementAmounts($purchaseOrderId);

        if ($amounts === null) {
            return '';
        }

        return implode('　', [
            __('dberp.fields.payable_amount').'：'.DberpNumberFormatter::money($amounts['payable_amount']),
            __('dberp.fields.paid_amount').'：'.DberpNumberFormatter::money($amounts['paid_amount']),
            __('dberp.fields.unpaid_amount').'：'.DberpNumberFormatter::money($amounts['unpaid_amount']),
        ]);
    }

    public function formatSalesOrderSettlementSummary(?int $salesOrderId): string
    {
        $amounts = $this->salesOrderSettlementAmounts($salesOrderId);

        if ($amounts === null) {
            return '';
        }

        return implode('　', [
            __('dberp.fields.receivable_amount').'：'.DberpNumberFormatter::money($amounts['receivable_amount']),
            __('dberp.fields.received_amount').'：'.DberpNumberFormatter::money($amounts['received_amount']),
            __('dberp.fields.unreceived_amount').'：'.DberpNumberFormatter::money($amounts['unreceived_amount']),
        ]);
    }

    public function suggestPaymentAmountFromPurchaseOrder(?int $purchaseOrderId): ?string
    {
        $amounts = $this->purchaseOrderSettlementAmounts($purchaseOrderId);

        if ($amounts === null) {
            return null;
        }

        return $this->suggestAmountFromOutstanding($amounts['unpaid_amount']);
    }

    public function suggestReceiptAmountFromSalesOrder(?int $salesOrderId): ?string
    {
        $amounts = $this->salesOrderSettlementAmounts($salesOrderId);

        if ($amounts === null) {
            return null;
        }

        return $this->suggestAmountFromOutstanding($amounts['unreceived_amount']);
    }

    private function suggestAmountFromOutstanding(string $outstandingAmount): ?string
    {
        if ((float) $outstandingAmount <= 0.00005) {
            return null;
        }

        return $this->formatAmount($outstandingAmount);
    }

    private function formatAmount(string $amount): string
    {
        return number_format((float) $amount, 4, '.', '');
    }
}
