<?php

namespace App\Services;

use App\Models\Currency;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class ExchangeRateService
{
    // Rates relative to USD — used when all API calls fail
    private const FALLBACK_RATES = [
        'USD' => 1.0,
        'EUR' => 0.92,
        'GBP' => 0.79,
        'INR' => 83.72,
        'CAD' => 1.37,
        'AUD' => 1.53,
        'JPY' => 149.50,
        'SGD' => 1.34,
        'AED' => 3.67,
        'PKR' => 278.50,
        'BDT' => 109.75,
        'CNY' => 7.24,
        'CHF' => 0.90,
        'MYR' => 4.72,
        'THB' => 35.10,
        'IDR' => 15750.0,
        'BRL' => 4.97,
        'MXN' => 17.15,
        'ZAR' => 18.63,
        'TRY' => 32.10,
    ];

    /**
     * Fetch live USD-based rates from public APIs (no key required).
     * Returns array: ['USD' => 1.0, 'EUR' => 0.92, 'INR' => 83.72, ...]
     */
    public function fetchUsdRates(): array
    {
        $apis = [
            'https://open.er-api.com/v6/latest/USD',
            'https://api.exchangerate-api.com/v4/latest/USD',
        ];

        foreach ($apis as $url) {
            try {
                $resp = Http::timeout(8)->get($url);
                if ($resp->successful()) {
                    $data = $resp->json();
                    $rates = $data['rates'] ?? $data['conversion_rates'] ?? null;
                    if (is_array($rates) && isset($rates['USD'])) {
                        return $rates;
                    }
                }
            } catch (\Exception $e) {
                Log::warning("ExchangeRateService: {$url} failed — {$e->getMessage()}");
            }
        }

        Log::warning('ExchangeRateService: all APIs failed, using fallback rates.');
        return self::FALLBACK_RATES;
    }

    /**
     * Update exchange rates for all active currencies in the DB.
     * Rates stored as: how many base-currency units = 1 unit of that currency.
     */
    public function updateAll(): array
    {
        $base = Currency::base();
        if (! $base) {
            return ['updated' => 0, 'source' => 'no_base'];
        }

        $usdRates = $this->fetchUsdRates();
        $baseInUsd = $usdRates[$base->code] ?? null;

        if (! $baseInUsd) {
            return ['updated' => 0, 'source' => 'base_not_in_rates'];
        }

        $updated = 0;
        $now     = now();

        foreach (Currency::active()->get() as $currency) {
            if ($currency->is_base) {
                $currency->update(['exchange_rate' => 1.000000, 'rates_updated_at' => $now]);
                $updated++;
                continue;
            }

            $currInUsd = $usdRates[$currency->code] ?? null;
            if ($currInUsd === null) continue;

            // How many base units = 1 unit of this currency
            // e.g. base=INR: baseInUsd=83.72, USD currInUsd=1.0 → 83.72/1.0 = 83.72 INR per 1 USD ✓
            $rate = $baseInUsd / $currInUsd;

            $currency->update(['exchange_rate' => round($rate, 6), 'rates_updated_at' => $now]);
            $updated++;
        }

        return ['updated' => $updated, 'source' => 'api'];
    }
}
