import { makeLogger } from "./logger.js";

const logger = makeLogger("btc-oracle");

const COINGECKO_URL =
  "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd";

interface CachedPrice {
  price: number;
  at: number;
}

let cache: CachedPrice | null = null;
const CACHE_MS = 60_000;

function fallbackPrice(): number {
  const raw = parseFloat(process.env.BTC_PRICE_USD_FALLBACK ?? "");
  return Number.isFinite(raw) && raw > 0 ? raw : 100_000;
}

/**
 * Returns the current BTC/USD price.
 * Caches for 60 s; falls back to BTC_PRICE_USD_FALLBACK env var (default $100,000)
 * on network failure so the service keeps running without internet access.
 */
export async function getBtcPriceUsd(): Promise<number> {
  if (cache && Date.now() - cache.at < CACHE_MS) {
    return cache.price;
  }

  try {
    const res = await fetch(COINGECKO_URL, {
      headers: { Accept: "application/json" },
      signal: AbortSignal.timeout(5_000),
    });

    if (!res.ok) throw new Error(`CoinGecko HTTP ${res.status}`);

    const data = (await res.json()) as { bitcoin?: { usd?: number } };
    const price = data?.bitcoin?.usd;
    if (!price || !Number.isFinite(price) || price <= 0) {
      throw new Error(`Unexpected CoinGecko response: ${JSON.stringify(data)}`);
    }

    cache = { price, at: Date.now() };
    return price;
  } catch (err) {
    const fb = fallbackPrice();
    logger.warn("price fetch failed — using fallback", {
      fallback_usd: fb,
      error: err instanceof Error ? err.message : String(err),
    });
    return fb;
  }
}

/**
 * Convert a USD amount to satoshis at the given BTC/USD price.
 * Always rounds up (ceil) so costs are fully covered; minimum 1 sat.
 */
export function usdToSats(usd: number, btcPriceUsd: number): number {
  if (usd <= 0) return 1;
  return Math.max(1, Math.ceil((usd / btcPriceUsd) * 1e8));
}
