import { CryptoAsset, Prisma } from "@prisma/client";
import { AppError } from "@/server/errors";
import { env, isProductionRuntime } from "@/server/env";

type CryptoRate = {
  asset: CryptoAsset;
  currency: "EUR";
  rate: Prisma.Decimal;
  source: string;
};

const KRAKEN_PAIRS: Record<CryptoAsset, string> = {
  BTC: "BTCEUR",
  ETH: "ETHEUR",
  USDC: "USDCEUR",
  USDT: "USDTEUR"
};

const LOCAL_RATES: Record<CryptoAsset, string> = {
  BTC: "58000",
  ETH: "3000",
  USDC: "0.92",
  USDT: "0.92"
};

export async function getCryptoEurRate(asset: CryptoAsset): Promise<CryptoRate> {
  const config = env();
  const providers = [config.CRYPTO_PRICE_PROVIDER, config.CRYPTO_PRICE_FALLBACK_PROVIDER]
    .map((provider) => provider.toLowerCase())
    .filter(Boolean);

  for (const provider of providers) {
    try {
      if (provider === "kraken") {
        return await rateFromKraken(asset);
      }

      if (provider === "coinbase") {
        return await rateFromCoinbase(asset);
      }
    } catch {
      continue;
    }
  }

  if (!isProductionRuntime(config)) {
    return {
      asset,
      currency: "EUR",
      rate: new Prisma.Decimal(LOCAL_RATES[asset]),
      source: "local-dev"
    };
  }

  throw new AppError("Crypto EUR rate unavailable", 503, "CRYPTO_RATE_UNAVAILABLE");
}

async function rateFromKraken(asset: CryptoAsset): Promise<CryptoRate> {
  const pair = KRAKEN_PAIRS[asset];
  const response = await fetch(`https://api.kraken.com/0/public/Ticker?pair=${pair}`, {
    cache: "no-store",
    headers: { accept: "application/json" }
  });

  if (!response.ok) {
    throw new Error("Kraken ticker unavailable");
  }

  const payload = (await response.json()) as {
    error?: string[];
    result?: Record<string, { c?: string[] }>;
  };

  if (payload.error?.length || !payload.result) {
    throw new Error("Kraken ticker error");
  }

  const first = Object.values(payload.result)[0];
  const price = first?.c?.[0];

  if (!price) {
    throw new Error("Kraken ticker price missing");
  }

  return { asset, currency: "EUR", rate: new Prisma.Decimal(price), source: "kraken" };
}

async function rateFromCoinbase(asset: CryptoAsset): Promise<CryptoRate> {
  const response = await fetch(`https://api.exchange.coinbase.com/products/${asset}-EUR/ticker`, {
    cache: "no-store",
    headers: { accept: "application/json" }
  });

  if (!response.ok) {
    throw new Error("Coinbase ticker unavailable");
  }

  const payload = (await response.json()) as { price?: string };

  if (!payload.price) {
    throw new Error("Coinbase ticker price missing");
  }

  return { asset, currency: "EUR", rate: new Prisma.Decimal(payload.price), source: "coinbase" };
}
