/**
 * Enhanced session naming with AI-powered auto-naming.
 *
 * Features:
 * - Manual naming: /session-name [name]
 * - Auto-naming command: /session-name --auto
 * - Automatic naming: triggers after 3 messages if no name set
 *
 * Auto-naming analyzes the conversation history and generates a concise,
 * descriptive name for the session using a cheap model (MiniMax).
 */

import { complete, type Message } from "@mariozechner/pi-ai";
import { getModel } from "@mariozechner/pi-ai";
import type { ExtensionAPI, SessionEntry } from "@mariozechner/pi-coding-agent";
import {
	BorderedLoader,
	convertToLlm,
	serializeConversation,
} from "@mariozechner/pi-coding-agent";
import * as fs from "node:fs";
import * as path from "node:path";
import * as os from "node:os";

const SYSTEM_PROMPT = `You are a session naming assistant. Given a conversation history, generate a short, descriptive session name (2-5 words) that captures the main topic or task.

Guidelines:
- Be concise but specific
- Use kebab-case or natural language
- Focus on the core task/question
- Avoid generic names like "discussion" or "conversation"
- No quotes, no punctuation at the end

Examples:
- "fix auth bug" -> "fix-auth-bug" or "authentication fix"
- "how do I deploy to vercel" -> "vercel deployment"
- "explain react hooks" -> "react hooks explanation"
- "optimize database queries" -> "db query optimization"

Output ONLY the session name, nothing else.`;

// Cheap model for auto-naming: Minimax from OpenCode Go
const AUTO_NAME_MODEL = getModel("opencode-go", "minimax-m2.5");

// Number of messages before auto-naming kicks in
const AUTO_NAME_THRESHOLD = 1;

// Debug log file
const LOG_FILE = path.join(os.homedir(), ".pi", "session-name-debug.log");

function log(message: string) {
	const timestamp = new Date().toISOString();
	const entry = `[${timestamp}] ${message}\n`;
	try {
		fs.appendFileSync(LOG_FILE, entry);
	} catch (e) {
		// ignore write errors
	}
}

export default function(pi: ExtensionAPI) {
	// Track if we've already attempted auto-naming for this session
	let autoNamedAttempted = false;

	// Listen for agent_end to auto-name sessions (non-blocking)
	pi.on("agent_end", (_event, ctx) => {
		log("=== agent_end triggered ===");
		log(`hasUI: ${ctx.hasUI}`);
		log(`current session name: ${pi.getSessionName()}`);
		log(`autoNamedAttempted: ${autoNamedAttempted}`);

		// Skip if already has a name or already attempted
		if (pi.getSessionName() || autoNamedAttempted) {
			log("Skipping: already has name or already attempted");
			return;
		}

		// Count user messages in the branch
		const branch = ctx.sessionManager.getBranch();
		const userMessages = branch.filter(
			(entry): entry is SessionEntry & { type: "message" } =>
				entry.type === "message" && entry.message.role === "user",
		);

		log(`Total entries in branch: ${branch.length}`);
		log(`User messages: ${userMessages.length}`);
		log(`Threshold: ${AUTO_NAME_THRESHOLD}`);

		// Only auto-name after threshold is reached
		if (userMessages.length < AUTO_NAME_THRESHOLD) {
			log("Skipping: below threshold");
			return;
		}

		// Mark as attempted so we don't try again
		autoNamedAttempted = true;
		log("Threshold reached, attempting auto-name");

		// Only auto-name in interactive mode
		if (!ctx.hasUI) {
			log("Skipping: no UI (non-interactive mode)");
			return;
		}

		// Gather conversation context
		const messages = branch
			.filter(
				(entry): entry is SessionEntry & { type: "message" } =>
					entry.type === "message",
			)
			.map((entry) => entry.message);

		log(`Total messages to analyze: ${messages.length}`);

		if (messages.length === 0) {
			log("No messages found, aborting");
			return;
		}

		// Convert to LLM format and serialize
		const llmMessages = convertToLlm(messages);
		const conversationText = serializeConversation(llmMessages);

		log(`Conversation text length: ${conversationText.length}`);

		// Truncate if too long (keep costs low)
		const maxChars = 4000;
		const truncatedText =
			conversationText.length > maxChars
				? conversationText.slice(0, maxChars) + "\n..."
				: conversationText;

		log(`Truncated text length: ${truncatedText.length}`);
		log("Starting background auto-name...");

		// Fire-and-forget: run auto-naming in background without blocking
		const doAutoName = async () => {
			const apiKey = await ctx.modelRegistry.getApiKey(AUTO_NAME_MODEL);
			log(`Got API key: ${apiKey ? "yes" : "no"}`);

			if (!apiKey) {
				log("No API key available, aborting");
				return;
			}

			const userMessage: Message = {
				role: "user",
				content: [
					{
						type: "text",
						text: `## Conversation History\n\n${truncatedText}\n\nGenerate a concise session name for this conversation.`,
					},
				],
				timestamp: Date.now(),
			};

			const response = await complete(
				AUTO_NAME_MODEL,
				{ systemPrompt: SYSTEM_PROMPT, messages: [userMessage] },
				{ apiKey },
			);

			log(`Response received, stopReason: ${response.stopReason}`);

			if (response.stopReason === "aborted") {
				log("Request was aborted");
				return;
			}

			const name = response.content
				.filter((c): c is { type: "text"; text: string } => c.type === "text")
				.map((c) => c.text.trim())
				.join(" ")
				.replace(/^[\"']|[\"']$/g, ""); // Remove surrounding quotes

			log(`Generated name: "${name}"`);

			// Clean up the generated name
			const cleanName = name
				.replace(/\n/g, " ")
				.replace(/\s+/g, " ")
				.trim()
				.slice(0, 50); // Max 50 chars

			log(`Cleaned name: "${cleanName}"`);

			if (cleanName) {
				pi.setSessionName(cleanName);
				ctx.ui.notify(`Auto-named: ${cleanName}`, "info");
				log(`Successfully set session name to: ${cleanName}`);
			} else {
				log("Cleaned name was empty, not setting");
			}
		};

		// Run in background without awaiting - don't block the agent
		doAutoName().catch((err) => {
			log(`ERROR: ${err}`);
			console.error("Auto-naming failed:", err);
		});
	});

	// Reset flag on new session
	pi.on("session_start", () => {
		log("=== session_start ===");
		autoNamedAttempted = false;
		log("Reset autoNamedAttempted to false");
	});

	pi.on("session_switch", () => {
		log("=== session_switch ===");
		autoNamedAttempted = false;
		log("Reset autoNamedAttempted to false");
	});

	// Manual command for setting/getting session name
	pi.registerCommand("session-name", {
		description:
			"Set, show, or auto-generate session name (usage: /session-name [name] or /session-name --auto)",
		handler: async (args, ctx) => {
			const trimmedArgs = args.trim();

			// Show current name if no args
			if (!trimmedArgs) {
				const current = pi.getSessionName();
				ctx.ui.notify(
					current ? `Session: ${current}` : "No session name set",
					"info",
				);
				return;
			}

			// Auto-generate name using AI
			if (trimmedArgs === "--auto" || trimmedArgs === "-a") {
				if (!ctx.hasUI) {
					ctx.ui.notify("Auto-naming requires interactive mode", "error");
					return;
				}

				// Gather conversation context
				const branch = ctx.sessionManager.getBranch();
				const messages = branch
					.filter(
						(entry): entry is SessionEntry & { type: "message" } =>
							entry.type === "message",
					)
					.map((entry) => entry.message);

				if (messages.length === 0) {
					ctx.ui.notify("No conversation to analyze", "error");
					return;
				}

				// Convert to LLM format and serialize
				const llmMessages = convertToLlm(messages);
				const conversationText = serializeConversation(llmMessages);

				// Truncate if too long (keep costs low)
				const maxChars = 4000;
				const truncatedText =
					conversationText.length > maxChars
						? conversationText.slice(0, maxChars) + "\n..."
						: conversationText;

				// Generate name with loader UI
				const result = await ctx.ui.custom<string | null>(
					(tui, theme, _kb, done) => {
						const loader = new BorderedLoader(
							tui,
							theme,
							"Generating session name...",
						);
						loader.onAbort = () => done(null);

						const doGenerate = async () => {
							const apiKey = await ctx.modelRegistry.getApiKey(AUTO_NAME_MODEL);

							const userMessage: Message = {
								role: "user",
								content: [
									{
										type: "text",
										text: `## Conversation History\n\n${truncatedText}\n\nGenerate a concise session name for this conversation.`,
									},
								],
								timestamp: Date.now(),
							};

							const response = await complete(
								AUTO_NAME_MODEL,
								{ systemPrompt: SYSTEM_PROMPT, messages: [userMessage] },
								{ apiKey, signal: loader.signal },
							);

							if (response.stopReason === "aborted") {
								return null;
							}

							const name = response.content
								.filter(
									(c): c is { type: "text"; text: string } => c.type === "text",
								)
								.map((c) => c.text.trim())
								.join(" ")
								.replace(/^[\"']|[\"']$/g, ""); // Remove surrounding quotes

							return name;
						};

						doGenerate()
							.then(done)
							.catch((err) => {
								console.error("Auto-naming failed:", err);
								done(null);
							});

						return loader;
					},
				);

				if (result === null) {
					ctx.ui.notify("Auto-naming cancelled", "info");
					return;
				}

				// Clean up the generated name
				const cleanName = result
					.replace(/\n/g, " ")
					.replace(/\s+/g, " ")
					.trim()
					.slice(0, 50); // Max 50 chars

				if (!cleanName) {
					ctx.ui.notify("Failed to generate name", "error");
					return;
				}

				pi.setSessionName(cleanName);
				ctx.ui.notify(`Session auto-named: ${cleanName}`, "info");
				return;
			}

			// Manual naming
			pi.setSessionName(trimmedArgs);
			ctx.ui.notify(`Session named: ${trimmedArgs}`, "info");
		},
	});
}
