<?php

declare(strict_types=1);

namespace App\Services\Billing;

use App\Models\Currency;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Facades\Cache;

class CurrencyService
{
    /**
     * Convert an amount from one currency to another.
     */
    public function convert(float $amount, string $from, string $to): float
    {
        $from = strtoupper($from);
        $to = strtoupper($to);

        if ($from === $to) {
            return $amount;
        }

        $currencies = $this->getEnabledCurrencies()->keyBy('code');

        $fromCurrency = $currencies->get($from);
        $toCurrency = $currencies->get($to);

        if (! $fromCurrency || ! $toCurrency) {
            return $amount;
        }

        // Convert to base currency first, then to target
        $fromRate = (float) $fromCurrency->exchange_rate;
        $toRate = (float) $toCurrency->exchange_rate;

        if ($fromRate <= 0) {
            return $amount;
        }

        $amountInBase = $amount / $fromRate;

        return round($amountInBase * $toRate, (int) $toCurrency->decimal_places);
    }

    /**
     * Get all enabled currencies, cached for 1 hour.
     *
     * @return Collection<int, Currency>
     */
    public function getEnabledCurrencies(): Collection
    {
        return Cache::remember('currencies:enabled', 3600, function (): Collection {
            return Currency::query()->enabled()->orderBy('code')->get();
        });
    }

    /**
     * Get the base currency.
     */
    public function getBaseCurrency(): Currency
    {
        return Cache::remember('currencies:base', 3600, function (): Currency {
            return Currency::query()->base()->firstOrFail();
        });
    }

    /**
     * Format a price with the currency symbol.
     */
    public function formatPrice(float $amount, string $currencyCode): string
    {
        $currency = $this->getEnabledCurrencies()->firstWhere('code', strtoupper($currencyCode));

        if (! $currency) {
            return number_format($amount, 2).' '.$currencyCode;
        }

        $formatted = number_format($amount, (int) $currency->decimal_places);

        return $currency->symbol.$formatted;
    }
}
