<?php

namespace App\Http\Requests;

use App\Http\Requests\Concerns\ValidatesSupplierPaymentFields;
use App\Models\Purchase;
use App\Models\PurchaseSupplier;
use App\Support\PurchaseCurrency;
use App\Support\SupplierAccountLedger;
use App\Support\SupplierPaymentExchange;
use App\Support\SupplierPaymentType;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator;

class StoreSupplierPaymentRequest extends FormRequest
{
    use ValidatesSupplierPaymentFields;

    public function authorize(): bool
    {
        return (bool) $this->user()?->can('supplier-payments.create');
    }

    /**
     * @return array<string, array<int, mixed>>
     */
    public function rules(): array
    {
        /** @var PurchaseSupplier $supplier */
        $supplier = $this->route('purchaseSupplier');

        return [
            'payment_type' => ['required', 'string', Rule::in(SupplierPaymentType::values())],
            'purchase_id' => [
                Rule::requiredIf(fn (): bool => $this->input('payment_type') === SupplierPaymentType::PURCHASE),
                'nullable',
                'integer',
                Rule::exists(Purchase::class, 'id')->where('supplier_id', $supplier->id),
            ],
            'bill_currency' => [
                Rule::requiredIf(fn (): bool => $this->input('payment_type') === SupplierPaymentType::OVERALL),
                'nullable',
                'string',
                Rule::in(PurchaseCurrency::values()),
            ],
            ...$this->supplierPaymentFieldRules(),
        ];
    }

    public function withValidator(Validator $validator): void
    {
        $validator->after(function (Validator $validator): void {
            if ($validator->errors()->isNotEmpty()) {
                return;
            }

            /** @var PurchaseSupplier $supplier */
            $supplier = $this->route('purchaseSupplier');
            $paymentType = (string) $this->input('payment_type');
            $paymentCurrency = (string) $this->input('currency');
            $paymentAmount = round((float) $this->input('amount'), 2);
            $exchangeRate = $this->filled('exchange_rate')
                ? round((float) $this->input('exchange_rate'), 4)
                : null;

            if ($paymentType === SupplierPaymentType::PURCHASE) {
                /** @var Purchase|null $purchase */
                $purchase = Purchase::query()->find((int) $this->input('purchase_id'));

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

                $billCurrency = $purchase->currency;

                if (SupplierPaymentExchange::requiresExchangeRate($paymentCurrency, $billCurrency)) {
                    if ($exchangeRate === null || $exchangeRate <= 0) {
                        $validator->errors()->add('exchange_rate', __('Exchange rate is required when payment currency differs from the bill.'));
                    }

                    $this->validateBillPaymentAmountRequired(
                        $validator,
                        $paymentCurrency,
                        $billCurrency,
                        $this->input('bill_payment_amount'),
                    );
                }

                return;
            }

            if ($paymentType === SupplierPaymentType::OVERALL) {
                $billCurrency = (string) $this->input('bill_currency');

                if (SupplierPaymentExchange::requiresExchangeRate($paymentCurrency, $billCurrency)) {
                    if ($exchangeRate === null || $exchangeRate <= 0) {
                        $validator->errors()->add('exchange_rate', __('Exchange rate is required when payment currency differs from the bill.'));
                    }

                    $this->validateBillPaymentAmountRequired(
                        $validator,
                        $paymentCurrency,
                        $billCurrency,
                        $this->input('bill_payment_amount'),
                    );
                }

                $billEquivalent = SupplierPaymentExchange::toBillCurrency(
                    $paymentAmount,
                    $paymentCurrency,
                    $billCurrency,
                    $exchangeRate,
                );

                if ($billEquivalent > 0.001) {
                    $openBills = SupplierAccountLedger::openPurchasesForSupplier($supplier, $billCurrency);

                    if ($openBills->isEmpty()) {
                        // Payment becomes full credit — allowed.
                    }
                }
            }
        });
    }
}
