<?php
declare(strict_types=1);

namespace App\Services;

use App\Database\Connection;
use PDO;
use RuntimeException;

class TipoCambioService
{
    /**
     * Obtiene tipo de cambio actual USD y EUR.
     *
     * @return array<string,mixed>|null
     */
    public static function obtenerActual(bool $forceRefresh = false): ?array
    {
        $pdo    = Connection::getPdo();
        $hoy    = date('Y-m-d');

        if (!$forceRefresh) {
            // Revisamos si ya tenemos USD y EUR para hoy
            $sql = "
                SELECT moneda, compra, venta
                FROM tipo_cambio
                WHERE fecha = :fecha
            ";
            $stmt = $pdo->prepare($sql);
            $stmt->execute([':fecha' => $hoy]);
            $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

            if ($rows) {
                $usd = null;
                $eur = null;
                foreach ($rows as $r) {
                    if ($r['moneda'] === 'USD') {
                        $usd = $r;
                    } elseif ($r['moneda'] === 'EUR') {
                        $eur = $r;
                    }
                }
                if ($usd && $eur) {
                    return [
                        'fecha' => $hoy,
                        'usd'   => [
                            'compra' => $usd['compra'] !== null ? (float)$usd['compra'] : null,
                            'venta'  => $usd['venta']  !== null ? (float)$usd['venta'] : null,
                        ],
                        'eur'   => [
                            'compra' => $eur['compra'] !== null ? (float)$eur['compra'] : null,
                            'venta'  => $eur['venta']  !== null ? (float)$eur['venta'] : null,
                        ],
                    ];
                }
            }
        }

        // 2) Llamar al API /indicadores/tc (dólar y euro juntos)
        $url  = 'https://api.hacienda.go.cr/indicadores/tc';
        $data = self::httpGetJson($url, $httpCode);

        if ($httpCode !== 200 || !is_array($data)) {
            return null;
        }

        // Estructura defensiva: intentamos encontrar los campos comunes
        // Ejemplos de docs mencionan que devuelve dólar y euro en un mismo recurso. :contentReference[oaicite:2]{index=2}
        $usdData = $data['dolar'] ?? $data['usd'] ?? null;
        $eurData = $data['euro']  ?? $data['eur'] ?? null;

        $usdCompra = $usdData['compra'] ?? ($usdData['compra_colones'] ?? null);
        $usdVenta  = $usdData['venta']  ?? ($usdData['venta_colones'] ?? null);
        $eurCompra = $eurData['compra'] ?? ($eurData['compra_colones'] ?? null);
        $eurVenta  = $eurData['venta']  ?? ($eurData['venta_colones'] ?? null);

        self::guardarTC($hoy, 'USD', $usdCompra, $usdVenta, $data);
        self::guardarTC($hoy, 'EUR', $eurCompra, $eurVenta, $data);

        return [
            'fecha' => $hoy,
            'usd'   => [
                'compra' => $usdCompra !== null ? (float)$usdCompra : null,
                'venta'  => $usdVenta  !== null ? (float)$usdVenta  : null,
            ],
            'eur'   => [
                'compra' => $eurCompra !== null ? (float)$eurCompra : null,
                'venta'  => $eurVenta  !== null ? (float)$eurVenta  : null,
            ],
        ];
    }

    private static function guardarTC(string $fecha, string $moneda, $compra, $venta, $raw): void
    {
        $pdo = Connection::getPdo();

        $sql = "
            INSERT INTO tipo_cambio
              (fecha, moneda, compra, venta, fuente, raw_response, creado_en)
            VALUES
              (:fecha, :moneda, :compra, :venta, 'hacienda', :raw, NOW())
            ON DUPLICATE KEY UPDATE
              compra       = VALUES(compra),
              venta        = VALUES(venta),
              raw_response = VALUES(raw_response),
              actualizado_en = NOW()
        ";

        $stmt = $pdo->prepare($sql);

        $rawJson = $raw !== null ? json_encode($raw, JSON_UNESCAPED_UNICODE) : null;

        $stmt->execute([
            ':fecha'  => $fecha,
            ':moneda' => $moneda,
            ':compra' => $compra !== null ? (float)$compra : null,
            ':venta'  => $venta !== null ? (float)$venta : null,
            ':raw'    => $rawJson,
        ]);
    }

    /**
     * @param-out int $httpCode
     * @return array<string,mixed>|array<int,mixed>|null
     */
    private static function httpGetJson(string $url, ?int &$httpCode): ?array
    {
        $httpCode = 0;

        $ch = curl_init();
        if ($ch === false) {
            throw new RuntimeException('No se pudo inicializar cURL');
        }

        curl_setopt_array($ch, [
            CURLOPT_URL            => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_TIMEOUT        => 10,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_SSL_VERIFYHOST => 2,
        ]);

        $response = curl_exec($ch);

        if ($response === false) {
            $httpCode = 0;
            curl_close($ch);
            return null;
        }

        $httpCode = (int)curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        $data = json_decode($response, true);
        if (!is_array($data)) {
            return null;
        }

        return $data;
    }
}
