import { appendFileSync, existsSync, mkdirSync, readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import {
	Key,
	matchesKey,
	truncateToWidth,
	visibleWidth,
} from "@singularity-forge/tui";
import { sfHome } from "../sf-home.js";

const LIMIT = 20;
const SCAN_LINE_LIMIT = 2000;
function promptHistoryPath() {
	return join(sfHome(), "agent", "prompt-history.jsonl");
}
function isEnvTruthy(value) {
	return ["1", "true", "TRUE", "yes", "YES"].includes(String(value ?? ""));
}
function parseEntryLine(line) {
	try {
		const text = line.trim();
		if (!text) return [];
		const entry = JSON.parse(text);
		if (
			!entry ||
			typeof entry !== "object" ||
			entry.version !== 1 ||
			typeof entry.prompt !== "string" ||
			entry.prompt.trim().length === 0 ||
			typeof entry.projectRoot !== "string" ||
			entry.projectRoot.trim().length === 0
		) {
			return [];
		}
		return [entry];
	} catch {
		return [];
	}
}
function readEntries() {
	try {
		const path = promptHistoryPath();
		if (!existsSync(path)) return [];
		return readFileSync(path, "utf-8")
			.split(/\r?\n/)
			.reverse()
			.slice(0, SCAN_LINE_LIMIT)
			.flatMap(parseEntryLine);
	} catch {
		return [];
	}
}
function normalizeHistory(history) {
	const seen = new Set();
	const merged = [];
	for (const item of history) {
		const text = String(item ?? "").trim();
		if (!text || seen.has(text)) continue;
		seen.add(text);
		merged.push(text);
		if (merged.length >= LIMIT) break;
	}
	return merged;
}
function appendEntries(entries) {
	try {
		const path = promptHistoryPath();
		mkdirSync(dirname(path), { recursive: true });
		appendFileSync(
			path,
			entries.map((entry) => JSON.stringify(entry)).join("\n") + "\n",
			{ encoding: "utf-8", mode: 0o600 },
		);
	} catch {
		/* non-fatal */
	}
}
export function readPromptHistory(basePath) {
	if (!basePath) return [];
	return normalizeHistory(
		readEntries()
			.filter((entry) => entry.projectRoot === basePath)
			.map((entry) => entry.prompt),
	);
}
export function appendPromptHistory(prompt, basePath, sessionId) {
	if (isEnvTruthy(process.env.SF_SKIP_PROMPT_HISTORY)) return;
	if (!basePath) return;
	const normalized = normalizeHistory([prompt]);
	if (!normalized.length) return;
	const now = Date.now();
	const entries = normalized.toReversed().map((prompt, index) => ({
		version: 1,
		prompt,
		projectRoot: basePath,
		sessionId: sessionId ?? null,
		timestamp: now - (normalized.length - index - 1),
	}));
	appendEntries(entries);
}
export function pushPromptHistory(history, text) {
	const t = text.trim();
	if (!t || history[0] === t) return;
	history.unshift(t);
	if (history.length > LIMIT) {
		history.length = LIMIT;
	}
}
function preview(text, maxWidth) {
	const c = text.replace(/\s+/g, " ").trim();
	return c ? truncateToWidth(c, maxWidth, "…") : "(empty)";
}
class PromptHistoryOverlay {
	tui;
	theme;
	done;
	items;
	sel = 0;
	cacheW = 0;
	cacheL = [];
	constructor(tui, theme, items, done) {
		this.tui = tui;
		this.theme = theme;
		this.items = items;
		this.done = done;
	}
	handleInput(data) {
		if (matchesKey(data, Key.escape) || matchesKey(data, Key.ctrl("c"))) {
			this.done(null);
			return;
		}
		if (matchesKey(data, Key.return) || matchesKey(data, Key.enter)) {
			this.done(this.items[this.sel] ?? null);
			return;
		}
		if (matchesKey(data, Key.down) || data === "j") {
			this.sel = Math.min(this.items.length - 1, this.sel + 1);
			this.invalidate();
			this.tui.requestRender();
			return;
		}
		if (matchesKey(data, Key.up) || data === "k") {
			this.sel = Math.max(0, this.sel - 1);
			this.invalidate();
			this.tui.requestRender();
			return;
		}
		if (data >= "1" && data <= "9") {
			const idx = parseInt(data, 10) - 1;
			if (idx >= 0 && idx < this.items.length) {
				this.done(this.items[idx] ?? null);
			}
		}
	}
	invalidate() {
		this.cacheW = 0;
	}
	render(width) {
		if (this.cacheW === width) return this.cacheL;
		const th = this.theme;
		const bw = Math.min(84, width - 4);
		const iw = bw - 4;
		const pad = (s) => s + " ".repeat(Math.max(0, width - visibleWidth(s)));
		const box = (s) => {
			const len = visibleWidth(s);
			return (
				th.fg("dim", "│ ") +
				s +
				" ".repeat(Math.max(0, bw - 2 - len)) +
				th.fg("dim", " │")
			);
		};
		const lines = [];
		lines.push(pad(th.fg("dim", "╭" + "─".repeat(bw) + "╮")));
		lines.push(pad(box(th.bold(th.fg("accent", "📜 Prompt History")))));
		lines.push(pad(th.fg("dim", "├" + "─".repeat(bw) + "┤")));
		lines.push(
			pad(
				box(
					th.fg(
						"dim",
						"↑/jk navigate • 1-9 quick pick • Enter insert • Esc cancel",
					),
				),
			),
		);
		lines.push(pad(box("")));
		for (let i = 0; i < this.items.length; i++) {
			const item = this.items[i];
			const p = preview(item, iw - 8);
			const ptr = i === this.sel ? th.fg("accent", "❯ ") : "  ";
			const num = i < 9 ? th.fg("dim", `${i + 1}`) : " ";
			const label = i === this.sel ? th.fg("accent", p) : p;
			lines.push(pad(box(`${ptr}${num}. ${label}`)));
		}
		lines.push(pad(box("")));
		lines.push(pad(th.fg("dim", "├" + "─".repeat(bw) + "┤")));
		lines.push(pad(box(th.fg("dim", `${this.items.length} prompts`))));
		lines.push(pad(th.fg("dim", "╰" + "─".repeat(bw) + "╯")));
		lines.push("");
		this.cacheL = lines;
		this.cacheW = width;
		return lines;
	}
}
export async function openPromptHistoryOverlay(ctx, basePath) {
	if (!ctx.hasUI) {
		ctx.ui.notify("Prompt history requires interactive mode", "error");
		return;
	}
	const items = readPromptHistory(basePath ?? undefined);
	if (!items.length) {
		ctx.ui.notify(
			"No prompt history yet. Send a message to build history.",
			"info",
		);
		return;
	}
	const selected = await ctx.ui.custom(
		(tui, theme, _kb, done) => {
			const o = new PromptHistoryOverlay(tui, theme, items, done);
			return {
				render: (w) => o.render(w),
				invalidate: () => o.invalidate(),
				handleInput: (d) => o.handleInput(d),
			};
		},
		{
			overlay: true,
			overlayOptions: {
				width: "90%",
				minWidth: 60,
				maxHeight: "85%",
				anchor: "center",
				backdrop: true,
			},
		},
	);
	if (selected) {
		ctx.ui.setEditorText(selected);
		ctx.ui.notify("Inserted prompt from history", "info");
	}
}
