'use strict';

const axios = require('axios');
const { query, queryOne } = require('../config/db');
const COINS = require('../config/coins');

const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes
const memCache = {};

// ── Get single rate ───────────────────────────────────────────────
async function getRate(coinKey, currency = 'USD') {
  const cacheKey = `${coinKey}_${currency}`;
  const now = Date.now();

  // Memory cache first (fastest)
  if (memCache[cacheKey] && now - memCache[cacheKey].ts < CACHE_TTL_MS) {
    return memCache[cacheKey].price;
  }

  // DB cache
  const dbRow = await queryOne(
    'SELECT price, updated_at FROM price_cache WHERE coin = ? AND currency = ?',
    [coinKey, currency.toUpperCase()]
  );

  if (dbRow && (now - new Date(dbRow.updated_at).getTime()) < CACHE_TTL_MS) {
    const price = parseFloat(dbRow.price);
    memCache[cacheKey] = { price, ts: now };
    return price;
  }

  // Fetch fresh
  const prices = await refreshAll(currency);
  return prices[coinKey] || null;
}

// ── Refresh all prices ────────────────────────────────────────────
async function refreshAll(currency = 'USD') {
  const cur = currency.toLowerCase();

  // Collect unique CoinGecko IDs
  const idMap = {};
  for (const [key, coin] of Object.entries(COINS)) {
    if (coin.coingecko) {
      if (!idMap[coin.coingecko]) idMap[coin.coingecko] = [];
      idMap[coin.coingecko].push(key);
    }
  }
  const ids = Object.keys(idMap).join(',');

  let data = {};

  // CoinGecko
  try {
    const cgKey = process.env.COINGECKO_API_KEY ? `&x_cg_api_key=${process.env.COINGECKO_API_KEY}` : '';
    const url = `https://api.coingecko.com/api/v3/simple/price?ids=${ids}&vs_currencies=${cur},usd${cgKey}`;
    const res = await axios.get(url, { timeout: 8000 });
    data = res.data;
  } catch (err) {
    console.warn('[PRICES] CoinGecko failed:', err.message);
  }

  const prices = {};

  // Map CoinGecko response back to our coin keys
  for (const [cgId, coinKeys] of Object.entries(idMap)) {
    if (data[cgId]) {
      const price = data[cgId][cur] || data[cgId]['usd'];
      if (price) {
        for (const key of coinKeys) {
          prices[key] = parseFloat(price);
        }
      }
    }
  }

  // Stablecoins always = 1
  for (const [key, coin] of Object.entries(COINS)) {
    if (['USDT_TRC20','USDT_ERC20','USDC'].includes(key)) {
      prices[key] = 1.0;
    }
  }

  // Binance fallback for any missing
  const missing = Object.keys(COINS).filter(k => !prices[k]);
  if (missing.length) {
    const binanceMap = { BTC:'BTCUSDT', ETH:'ETHUSDT', LTC:'LTCUSDT', BNB:'BNBUSDT', DOGE:'DOGEUSDT', SOL:'SOLUSDT', MATIC:'MATICUSDT', TRX:'TRXUSDT', AVAX:'AVAXUSDT', ARB:'ARBUSDT' };
    for (const key of missing) {
      if (binanceMap[key]) {
        try {
          const r = await axios.get(`https://api.binance.com/api/v3/ticker/price?symbol=${binanceMap[key]}`, { timeout: 4000 });
          if (r.data && r.data.price) prices[key] = parseFloat(r.data.price);
        } catch (e) {}
      }
    }
  }

  // Save to DB + memory cache
  const now = Date.now();
  for (const [key, price] of Object.entries(prices)) {
    const cacheKey = `${key}_${currency.toUpperCase()}`;
    memCache[cacheKey] = { price, ts: now };

    await query(
      `INSERT INTO price_cache (coin, currency, price, source)
       VALUES (?, ?, ?, 'coingecko')
       ON DUPLICATE KEY UPDATE price = VALUES(price), updated_at = NOW()`,
      [key, currency.toUpperCase(), price]
    ).catch(() => {});
  }

  console.log(`[PRICES] Refreshed ${Object.keys(prices).length} prices for ${currency}`);
  return prices;
}

// ── Convert fiat → crypto ─────────────────────────────────────────
function fiatToCrypto(fiatAmount, rate, decimals = 8) {
  if (!rate || rate <= 0) return '0';
  const crypto = parseFloat(fiatAmount) / rate;
  return crypto.toFixed(decimals).replace(/\.?0+$/, '');
}

// ── Get all prices (for checkout display) ────────────────────────
async function getAllRates(currency = 'USD') {
  const rows = await query(
    'SELECT coin, price FROM price_cache WHERE currency = ? AND updated_at > DATE_SUB(NOW(), INTERVAL 10 MINUTE)',
    [currency.toUpperCase()]
  );

  if (rows.length < 5) {
    return refreshAll(currency);
  }

  const result = {};
  rows.forEach(r => { result[r.coin] = parseFloat(r.price); });
  return result;
}

// ── ETH gas estimate ──────────────────────────────────────────────
async function getEthGasUsd() {
  try {
    const ethPrice = await getRate('ETH', 'USD');
    const r = await axios.get('https://api.ethgasstation.info/api/fee-estimate', { timeout: 5000 });
    const gwei = r.data && r.data.gasPrice && r.data.gasPrice.fast ? r.data.gasPrice.fast : 30;
    return (gwei * 21000 * 1e-9) * ethPrice;
  } catch (e) {
    return 25; // fallback $25 gas estimate
  }
}

module.exports = { getRate, refreshAll, fiatToCrypto, getAllRates, getEthGasUsd };
