/**
 * Yield Sandbox — pure client-side compound interest simulator.
 * No server dependencies. Uses live DeFi Llama rates when available,
 * falls back to hardcoded mock rates.
 */

export type SandboxProtocol = "aave-v3" | "morpho-blue";
export type SandboxChain = "1" | "8453";
export type SandboxAsset = "USDC" | "USDT" | "DAI";

export interface YieldPoint {
	days: number;
	balance: number;
	earnings: number;
	dailyRate: number;
}

export interface SandboxResult {
	principal: number;
	apy: number;
	isLive: boolean;
	protocol: string;
	chainId: string;
	asset: string;
	milestones: YieldPoint[];
}

export interface ProtocolComparison {
	protocol: SandboxProtocol;
	chainId: SandboxChain;
	label: string;
	apy: number;
	isLive: boolean;
	earnings: number;
	balance: number;
}

interface LiveRate {
	protocol: string;
	chainId: string;
	asset: string;
	apy: number;
}

// ── Realistic fallback APYs (updated periodically) ──

const MOCK_FALLBACK_RATES: Record<string, number> = {
	"aave-v3:1:USDC": 3.82,
	"aave-v3:1:USDT": 3.61,
	"aave-v3:1:DAI": 3.95,
	"aave-v3:8453:USDC": 4.12,
	"aave-v3:8453:DAI": 3.74,
	"morpho-blue:1:USDC": 5.23,
	"morpho-blue:1:USDT": 4.87,
	"morpho-blue:8453:USDC": 5.52,
};

const MILESTONE_DAYS = [1, 7, 30, 90, 180, 365, 730, 1825];

const PROTOCOL_LABELS: Record<string, string> = {
	"aave-v3:1": "Aave V3 Ethereum",
	"aave-v3:8453": "Aave V3 Base",
	"morpho-blue:1": "Morpho Ethereum",
	"morpho-blue:8453": "Morpho Base",
};

// ── Core compound interest ──

export function computeYieldAtDays(
	principal: number,
	apy: number,
	days: number,
	compoundFreq = 365,
): YieldPoint {
	const r = apy / 100;
	const t = days / 365;
	const balance = principal * Math.pow(1 + r / compoundFreq, compoundFreq * t);
	const earnings = balance - principal;
	const dailyRate = days > 0 ? earnings / days : 0;
	return { days, balance, earnings, dailyRate };
}

// ── Full milestone simulation ──

export function simulateYield(config: {
	principal: number;
	apy: number;
	isLive: boolean;
	protocol: string;
	chainId: string;
	asset: string;
	compoundFreq?: number;
}): SandboxResult {
	const freq = config.compoundFreq ?? 365;
	const milestones = MILESTONE_DAYS.map((d) =>
		computeYieldAtDays(config.principal, config.apy, d, freq),
	);
	return {
		principal: config.principal,
		apy: config.apy,
		isLive: config.isLive,
		protocol: config.protocol,
		chainId: config.chainId,
		asset: config.asset,
		milestones,
	};
}

// ── APY resolution: live > mock ──

export function resolveApy(
	protocol: string,
	chainId: string,
	asset: string,
	liveRates?: LiveRate[],
): { apy: number; isLive: boolean } {
	if (liveRates?.length) {
		const match = liveRates.find(
			(r) => r.protocol === protocol && r.chainId === chainId && r.asset === asset,
		);
		if (match && match.apy > 0) return { apy: match.apy, isLive: true };
	}
	const key = `${protocol}:${chainId}:${asset}`;
	const fallback = MOCK_FALLBACK_RATES[key];
	return fallback != null ? { apy: fallback, isLive: false } : { apy: 0, isLive: false };
}

// ── Cross-protocol comparison ──

export function buildProtocolComparisons(
	asset: SandboxAsset,
	principal: number,
	days: number,
	liveRates?: LiveRate[],
): ProtocolComparison[] {
	const combos: Array<{ protocol: SandboxProtocol; chainId: SandboxChain }> = [
		{ protocol: "aave-v3", chainId: "1" },
		{ protocol: "aave-v3", chainId: "8453" },
		{ protocol: "morpho-blue", chainId: "1" },
		{ protocol: "morpho-blue", chainId: "8453" },
	];

	const results: ProtocolComparison[] = [];

	for (const { protocol, chainId } of combos) {
		const { apy, isLive } = resolveApy(protocol, chainId, asset, liveRates);
		if (apy <= 0) continue;

		const { balance, earnings } = computeYieldAtDays(principal, apy, days);
		const label = PROTOCOL_LABELS[`${protocol}:${chainId}`] || `${protocol} ${chainId}`;

		results.push({ protocol, chainId, label, apy, isLive, earnings, balance });
	}

	results.sort((a, b) => b.apy - a.apy);
	return results;
}
