import type {
	ExtensionContext,
	ReadonlyFooterDataProvider,
	Theme,
} from "@singularity-forge/pi-coding-agent";
import { truncateToWidth, visibleWidth } from "@singularity-forge/pi-tui";
import { refreshGitStatus } from "./git.js";

const RESET = "\x1b[0m";
const BOLD = "\x1b[1m";

const SE = {
	ember40: "#ff8838",
	gray60: "#8d877a",
	stone60: "#6b6659",
	paper: "#f7f5f1",
	success: "#24a148",
	error: "#da1e28",
} as const;

type Tone = "muted" | "accent" | "text" | "success" | "warning" | "error";

function hexToRgb(hex: string): { r: number; g: number; b: number } {
	const cleaned = hex.replace("#", "");
	return {
		r: parseInt(cleaned.slice(0, 2), 16),
		g: parseInt(cleaned.slice(2, 4), 16),
		b: parseInt(cleaned.slice(4, 6), 16),
	};
}

function ansiFg(hex: string, text: string, bold = false): string {
	// Use 16-color ANSI codes for Termius compatibility
	// Map hex colors to nearest standard ANSI color
	const { r, g, b } = hexToRgb(hex);
	const brightness = (r + g + b) / 3;

	let colorCode: number;
	if (brightness < 50) {
		colorCode = 30; // black
	} else if (brightness < 100) {
		colorCode = 90; // bright black
	} else if (r > g + b) {
		colorCode = bold ? 91 : 31; // red
	} else if (g > r + b) {
		colorCode = bold ? 92 : 32; // green
	} else if (b > r + g) {
		colorCode = bold ? 94 : 34; // blue
	} else if (r > 200 && g > 150) {
		colorCode = bold ? 93 : 33; // yellow/orange
	} else if (r > 200 && g < 100 && b > 150) {
		colorCode = bold ? 95 : 35; // magenta
	} else if (g > 200 && b > 150) {
		colorCode = bold ? 96 : 36; // cyan
	} else if (brightness > 200) {
		colorCode = bold ? 97 : 37; // white
	} else {
		colorCode = bold ? 97 : 37; // default white
	}

	return `\x1b[${bold ? "1;" : ""}${colorCode}m${text}${RESET}`;
}

function toneHex(tone: Tone): string {
	switch (tone) {
		case "accent":
		case "warning":
			return SE.ember40;
		case "success":
			return SE.success;
		case "error":
			return SE.error;
		case "text":
			return SE.paper;
		default:
			return SE.gray60;
	}
}

function chip(label: string, value: string, tone: Tone = "text"): string {
	return `${ansiFg(SE.gray60, `${label} `)}${ansiFg(toneHex(tone), value)}`;
}

function join(parts: string[]): string {
	return parts.filter(Boolean).join(ansiFg(SE.stone60, " | "));
}

function shorten(text: string, max: number): string {
	return text.length > max ? `${text.slice(0, Math.max(0, max - 3))}...` : text;
}

function getSessionStats(ctx: ExtensionContext) {
	let cost = 0;
	let tokens = 0;
	let cxPct = 0;

	try {
		for (const entry of ctx.sessionManager.getEntries()) {
			if (entry.type === "message") {
				const msg = (entry as any).message;
				if (msg?.role === "assistant" && msg.usage) {
					cost += msg.usage.cost?.total || 0;
					tokens += (msg.usage.input || 0) + (msg.usage.output || 0);
				}
			}
		}
		const cx = ctx.getContextUsage?.();
		if (cx?.percent != null) cxPct = cx.percent;
	} catch {
		/* ignore */
	}

	return { cost, tokens, cxPct };
}

export function renderFooter(
	_theme: Theme,
	footerData: ReadonlyFooterDataProvider,
	ctx: ExtensionContext,
	width: number,
): string[] {
	const git = refreshGitStatus(process.cwd());
	const { cost, cxPct } = getSessionStats(ctx);

	const leftParts: string[] = [];
	if (git.repo) {
		leftParts.push(ansiFg(SE.ember40, git.repo, true));
	} else {
		leftParts.push(`${BOLD}${ansiFg(SE.ember40, "SF")}`);
	}

	if (git.branch) {
		leftParts.push(chip("branch", git.branch, "muted"));
		const state = git.dirty ? "dirty" : git.untracked ? "new" : "clean";
		leftParts.push(chip("state", state, state === "clean" ? "success" : "warning"));
		if (git.added || git.deleted) {
			leftParts.push(chip("diff", `+${git.added}/-${git.deleted}`, "warning"));
		}
		if (git.ahead || git.behind) {
			leftParts.push(chip("sync", `${git.ahead} ahead ${git.behind} behind`, "warning"));
		}
		if (git.lastCommit) {
			leftParts.push(chip("last", `${git.lastCommit.timeAgo} ${shorten(git.lastCommit.message, 26)}`, "muted"));
		}
	}

	const statuses = Array.from(footerData.getExtensionStatuses().entries())
		.sort(([a], [b]) => a.localeCompare(b))
		.map(([, text]) => text.trim())
		.filter(Boolean);
	if (statuses.length) {
		leftParts.push(chip("status", statuses.join(" "), "accent"));
	}

	const rightParts: string[] = [];
	if (ctx.model) {
		rightParts.push(chip("model", `${ctx.model.provider}/${ctx.model.id}`, "text"));
	}
	if (cost > 0) {
		rightParts.push(chip("spent", `$${cost.toFixed(2)}`, "warning"));
	}
	const cxTone: Tone = cxPct >= 85 ? "error" : cxPct >= 60 ? "warning" : "success";
	rightParts.push(chip("ctx", `${Math.round(cxPct)}%`, cxTone));

	let rightLine = join(rightParts);
	const maxRightWidth = Math.max(16, Math.floor(width * 0.55));
	if (visibleWidth(rightLine) > maxRightWidth) {
		rightLine = truncateToWidth(rightLine, maxRightWidth, ansiFg(SE.gray60, "..."));
	}

	const rightWidth = visibleWidth(rightLine);
	const leftBudget = Math.max(1, width - rightWidth - 2);
	const leftLine = truncateToWidth(join(leftParts), leftBudget, ansiFg(SE.gray60, "..."));
	const gap = Math.max(1, width - visibleWidth(leftLine) - rightWidth);
	const line = leftLine + " ".repeat(gap) + rightLine;

	return [truncateToWidth(line, width, ansiFg(SE.gray60, "..."))];
}
