import { ethers } from 'ethers';
import { primeLiveReferencePriceUsd } from './canonical-price-oracle';

const ROUND_DATA_ABI = [
  'function latestRoundData() view returns (uint80 roundId,int256 answer,uint256 startedAt,uint256 updatedAt,uint80 answeredInRound)',
];

const DEFAULT_RPC = 'http://192.168.11.211:8545';
const DEFAULT_AGGREGATOR = '0x99b3511a2d315a497c8112c1fdd8d508d4b1e506';
const DEFAULT_PROXY = '0x3304b747e565a97ec8ac220b0b6a1f6ffdb837e6';

interface CachedPrice {
  priceUsd: number;
  expiresAt: number;
  source: 'aggregator' | 'proxy';
}

let cachedEthUsd: CachedPrice | undefined;

function readAggregatorAddress(): string {
  return (
    process.env.AGGREGATOR_ADDRESS?.trim() ||
    process.env.ORACLE_AGGREGATOR_ADDRESS?.trim() ||
    DEFAULT_AGGREGATOR
  ).toLowerCase();
}

function readProxyAddress(): string {
  return (
    process.env.ORACLE_PROXY_ADDRESS?.trim() ||
    process.env.ORACLE_PROXY?.trim() ||
    DEFAULT_PROXY
  ).toLowerCase();
}

function readRpcUrl(): string {
  return (
    process.env.RPC_URL_138?.trim() ||
    process.env.CHAIN138_RPC_URL?.trim() ||
    DEFAULT_RPC
  );
}

async function readEthUsdFromContract(address: string, rpcUrl: string): Promise<number | undefined> {
  const provider = new ethers.JsonRpcProvider(rpcUrl);
  const contract = new ethers.Contract(address, ROUND_DATA_ABI, provider);
  const result = await contract.latestRoundData();
  const answer = Number(result.answer ?? result[1]);
  if (!Number.isFinite(answer) || answer <= 0) {
    return undefined;
  }
  return answer / 1e8;
}

/**
 * Live ETH/USD from Chain 138 on-chain feeds (aggregator preferred, proxy fallback).
 */
export async function getChain138EthUsdOnChain(): Promise<{ priceUsd: number; source: 'aggregator' | 'proxy' } | undefined> {
  if (cachedEthUsd && cachedEthUsd.expiresAt > Date.now()) {
    return { priceUsd: cachedEthUsd.priceUsd, source: cachedEthUsd.source };
  }

  const rpcUrl = readRpcUrl();
  const aggregator = readAggregatorAddress();
  const proxy = readProxyAddress();

  for (const [address, source] of [[aggregator, 'aggregator'], [proxy, 'proxy']] as const) {
    try {
      const priceUsd = await readEthUsdFromContract(address, rpcUrl);
      if (priceUsd != null && priceUsd > 0) {
        cachedEthUsd = { priceUsd, expiresAt: Date.now() + 60_000, source };
        return { priceUsd, source };
      }
    } catch {
      // try next feed
    }
  }

  return undefined;
}

export function clearChain138OnChainPriceCache(): void {
  cachedEthUsd = undefined;
}

export async function refreshChain138LiveReferencePrices(chainId: number): Promise<void> {
  if (chainId !== 138) {
    return;
  }
  const eth = await getChain138EthUsdOnChain();
  if (eth) {
    primeLiveReferencePriceUsd('ETH', eth.priceUsd);
  }
}
