<?php

namespace App\Http\Controllers;

use App\Http\Requests\StoreCurrencyExchangeRequest;
use App\Http\Requests\UpdateCurrencyExchangeRequest;
use App\Models\CurrencyExchange;
use App\Models\Saraf;
use App\Models\SarafPaymentAllocation;
use App\Support\NumberFormat;
use Illuminate\Http\RedirectResponse;
use Inertia\Inertia;
use Inertia\Response;

class CurrencyExchangeController extends Controller
{
    public function index(): Response
    {
        $exchanges = CurrencyExchange::query()
            ->with('saraf:id,name')
            ->orderByDesc('exchange_date')
            ->orderByDesc('id')
            ->get()
            ->map(fn (CurrencyExchange $exchange): array => $this->exchangeListPayload($exchange));

        return Inertia::render('sarafi/currency-exchange/index', [
            'exchanges' => $exchanges,
        ]);
    }

    public function show(CurrencyExchange $currencyExchange): Response
    {
        $currencyExchange->load('saraf:id,name');

        return Inertia::render('sarafi/currency-exchange/show', [
            'exchange' => $this->exchangeDetailPayload($currencyExchange),
        ]);
    }

    public function create(): Response
    {
        return Inertia::render('sarafi/currency-exchange/create', [
            'sarafs' => $this->activeSarafs(),
        ]);
    }

    public function store(StoreCurrencyExchangeRequest $request): RedirectResponse
    {
        CurrencyExchange::query()->create($request->validated());

        return redirect()
            ->route('sarafi.currency-exchange.index')
            ->with('status', __('Currency exchange recorded.'));
    }

    public function edit(CurrencyExchange $currencyExchange): Response
    {
        $currencyExchange->load('saraf:id,name');

        return Inertia::render('sarafi/currency-exchange/edit', [
            'exchange' => $this->exchangeFormPayload($currencyExchange),
            'sarafs' => $this->sarafsForExchange($currencyExchange),
            'minReceiveDollar' => $this->minReceiveDollar($currencyExchange),
        ]);
    }

    public function update(
        UpdateCurrencyExchangeRequest $request,
        CurrencyExchange $currencyExchange,
    ): RedirectResponse {
        $currencyExchange->fill($request->validated());
        $currencyExchange->save();

        return redirect()
            ->route('sarafi.currency-exchange.show', $currencyExchange)
            ->with('status', __('Currency exchange updated.'));
    }

    /**
     * @return array<string, mixed>
     */
    private function exchangeListPayload(CurrencyExchange $exchange): array
    {
        return [
            'id' => $exchange->id,
            'saraf_id' => $exchange->saraf_id,
            'saraf_name' => $exchange->saraf?->name,
            'exchange_date' => $exchange->exchange_date?->toDateString(),
            'total_afn' => $exchange->total_afn,
            'dollar_difference_price' => $exchange->dollar_difference_price,
            'dollar_price' => $exchange->dollar_price,
            'total_dollar' => $exchange->total_dollar,
            'receive_dollar' => $exchange->receive_dollar,
            'remain_dollar_on_saraf' => $exchange->remain_dollar_on_saraf,
        ];
    }

    /**
     * @return array<string, mixed>
     */
    private function exchangeDetailPayload(CurrencyExchange $exchange): array
    {
        $effectiveRate = round(
            (float) $exchange->dollar_price + (float) $exchange->dollar_difference_price,
            4,
        );

        return [
            ...$this->exchangeListPayload($exchange),
            'saraf_name' => $exchange->saraf?->name,
            'effective_rate' => NumberFormat::rate($effectiveRate),
            'allocated_receive_dollar' => NumberFormat::money($this->allocatedReceiveDollar($exchange)),
        ];
    }

    /**
     * @return array<string, mixed>
     */
    private function exchangeFormPayload(CurrencyExchange $exchange): array
    {
        return [
            'id' => $exchange->id,
            'saraf_id' => $exchange->saraf_id,
            'exchange_date' => $exchange->exchange_date?->toDateString(),
            'total_afn' => $this->trimDecimal($exchange->total_afn),
            'dollar_difference_price' => $this->trimDecimal($exchange->dollar_difference_price, 4),
            'dollar_price' => $this->trimDecimal($exchange->dollar_price, 4),
            'receive_dollar' => $this->trimDecimal($exchange->receive_dollar),
        ];
    }

    /**
     * @return list<array{id: int, name: string}>
     */
    private function activeSarafs(): array
    {
        return Saraf::query()
            ->where('is_active', true)
            ->orderBy('name')
            ->get(['id', 'name'])
            ->map(fn (Saraf $saraf): array => [
                'id' => $saraf->id,
                'name' => $saraf->name,
            ])
            ->values()
            ->all();
    }

    /**
     * @return list<array{id: int, name: string}>
     */
    private function sarafsForExchange(CurrencyExchange $exchange): array
    {
        return Saraf::query()
            ->where('is_active', true)
            ->orWhere('id', $exchange->saraf_id)
            ->orderBy('name')
            ->get(['id', 'name'])
            ->unique('id')
            ->map(fn (Saraf $saraf): array => [
                'id' => $saraf->id,
                'name' => $saraf->name,
            ])
            ->values()
            ->all();
    }

    private function allocatedReceiveDollar(CurrencyExchange $exchange): float
    {
        return round((float) SarafPaymentAllocation::query()
            ->where('currency_exchange_id', $exchange->id)
            ->sum('amount'), 2);
    }

    private function minReceiveDollar(CurrencyExchange $exchange): string
    {
        return NumberFormat::money($this->allocatedReceiveDollar($exchange));
    }

    private function trimDecimal(?string $value, int $maxDecimals = 2): string
    {
        if ($value === null || $value === '') {
            return '';
        }

        return NumberFormat::forInput($value, $maxDecimals);
    }
}
