// AGPL-3.0-only
//
// This is free software for the public good of a permacomputer
// hosted at permacomputer.com, an always-on computer by the people, for the
// people. One which is durable, easy to repair, and distributed like tap water
// for machine learning intelligence.
//
// The permacomputer is community-owned infrastructure optimized around
// four values:
//
//   TRUTH    - First principles, math & science, open source code
//   FREEDOM  - Voluntary partnerships, freedom from tyranny & corporate control
//   HARMONY  - Minimal waste, self-renewing systems with diverse connections
//   LOVE     - Be yourself without hurting others, cooperation through natural law
//
// This software contributes to that vision by making machine learning
// accessible to everyone through a free, open, embeddable chat interface.
// Code is seeds to sprout on any abandoned technology.
//
// Learn more: https://www.permacomputer.com
//
// NO WARRANTY. THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
//
// Copyright 2025-2026 TimeHexOn & foxhop & russell@unturf
// https://www.permacomputer.com

// Main Hermes AI modal functionality - COMPLETE WORKING VERSION
import { marked } from "https://cdn.jsdelivr.net/npm/marked/lib/marked.esm.js";
import hljs from "https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/es/highlight.min.js";
import { setSystemMessageAppend } from "./config.js";
import { extractWebpageContent, buildPageAnalysisPrompt, parsePageAnalysis, buildAnalysisContext } from "./content.js";
import { computePageIntelligence, formatPageIntelligence } from "./page-intelligence.js";
import {
	detectCurrentTheme,
	getThemeColors,
	initializeChunkFiveFont,
} from "./ui-themes.js";
import {
	getUIText,
	getUserLanguagePreference,
	setUserLanguagePreference,
} from "./ui-translations.js";
import { UncloseVault } from "./vault.js";

// Load CryptoJS if not already loaded
async function ensureCryptoJS() {
	if (typeof CryptoJS !== "undefined") return true;

	return new Promise((resolve) => {
		const script = document.createElement("script");
		script.src =
			"https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.2.0/crypto-js.min.js";
		script.onload = () => resolve(true);
		script.onerror = () => {
			console.warn("Failed to load CryptoJS - vault features disabled");
			resolve(false);
		};
		document.head.appendChild(script);
	});
}

// Get USE_CUSTOM_STYLING from window or default
const _USE_CUSTOM_STYLING = window.UNCLOSEAI_CUSTOM_STYLING !== false;

// Helper function to parse model:voice format
function parseVoiceSelection(selectedValue) {
	// Check if format is "model:voice" or legacy "voice"
	if (selectedValue.includes(":")) {
		const [model, voice] = selectedValue.split(":");
		return { model, voice };
	}
	// Legacy format - assume tts-1-qwen model
	return { model: "tts-1-qwen", voice: selectedValue };
}

// Import required functions dynamically to avoid circular dependencies
async function speakChatText(text, voiceSelection, speed) {
	const { handleTTS } = await import("./tts.js");
	const { model, voice } = parseVoiceSelection(voiceSelection);
	return await handleTTS(text, voice, speed, model);
}

async function* sendMessage(message) {
	try {
		const chatModule = await import("./chat.js");
		if (!chatModule.sendMessage) {
			console.error("sendMessage not found in chat.js module:", chatModule);
			throw new Error("sendMessage function not found in chat.js");
		}
		yield* chatModule.sendMessage(message);
	} catch (error) {
		console.error("Error in sendMessage wrapper:", error);
		throw error;
	}
}

async function* sendMessageWithCustomHistory(history) {
	const { sendMessageWithCustomHistory } = await import("./chat.js");
	yield* sendMessageWithCustomHistory(history);
}

async function getChatHistory() {
	const { getChatHistory } = await import("./chat.js");
	return getChatHistory();
}

async function updateChatHistory(history) {
	const { updateChatHistory } = await import("./chat.js");
	return updateChatHistory(history);
}

async function clearConversationHistory() {
	const { clearConversationHistory } = await import("./storage.js");
	return clearConversationHistory();
}

async function loadConversationHistory() {
	const { loadConversationHistory } = await import("./storage.js");
	return loadConversationHistory();
}

async function saveConversationHistory(history) {
	const { saveConversationHistory } = await import("./storage.js");
	return saveConversationHistory(history);
}

async function fetchModelsFromEndpoints() {
	const { fetchModelsFromEndpoints } = await import("./models.js");
	return fetchModelsFromEndpoints();
}

async function getSelectedModel() {
	const { getSelectedModel } = await import("./models.js");
	return getSelectedModel();
}

// Helper function to add copy and run buttons to code blocks
function addCodeBlockCopyButtons(element) {
	const codeBlocks = element.querySelectorAll("pre code");
	codeBlocks.forEach((codeBlock) => {
		const pre = codeBlock.parentElement;
		if (pre.tagName.toLowerCase() === "pre") {
			// Check if buttons already exist to avoid duplicates
			const existingBtn = pre.querySelector(".uncloseai-code-copy-btn");
			if (existingBtn) {
				return;
			}

			// Make the pre element relative for positioning
			pre.style.position = "relative";

			// Create button container for both copy and run buttons
			const buttonContainer = document.createElement("div");
			buttonContainer.style.position = "absolute";
			buttonContainer.style.top = "8px";
			buttonContainer.style.right = "8px";
			buttonContainer.style.display = "flex";
			buttonContainer.style.gap = "4px";
			buttonContainer.style.zIndex = "10";
			buttonContainer.style.pointerEvents = "auto";

			// Create copy button
			const copyBtn = document.createElement("button");
			copyBtn.className = "uncloseai-code-copy-btn";
			copyBtn.textContent = "📋";
			copyBtn.title = "Copy code";

			copyBtn.onclick = async () => {
				try {
					await navigator.clipboard.writeText(codeBlock.textContent);
					copyBtn.textContent = "✓";
					setTimeout(() => {
						copyBtn.textContent = "📋";
					}, 2000);
				} catch (error) {
					console.error("Failed to copy code:", error);
				}
			};

			buttonContainer.appendChild(copyBtn);

			// Code execution button disabled - sandbox service not running
			// To re-enable, uncomment the runBtn code below

			pre.appendChild(buttonContainer);
		}
	});
}

// Function to refresh modal UI when language changes
function refreshModalUI() {
	// Refresh all elements with data-i18n attributes in the modal
	const modal = document.getElementById("uncloseai-embedded-modal");
	if (!modal) return;

	const elementsWithI18n = modal.querySelectorAll("[data-i18n]");
	elementsWithI18n.forEach((element) => {
		const key = element.getAttribute("data-i18n");
		const translatedText = getUIText(key);

		if (element.tagName === "INPUT" && element.type === "text") {
			element.placeholder = translatedText;
		} else if (element.tagName === "BUTTON" || element.tagName === "LABEL") {
			// Preserve any icons/emojis at the start
			const currentText = element.textContent;
			const iconMatch = currentText.match(/^[^\w\s]+\s*/);
			const icon = iconMatch ? iconMatch[0] : "";
			element.textContent = icon + translatedText;
		} else {
			element.textContent = translatedText;
		}
	});

	// Update any specific elements that need special handling
	const titleElement = modal.querySelector("h1");
	if (titleElement) {
		titleElement.innerHTML = `<span style="font-family: 'ChunkFiveRegular', monospace;">uncloseai.</span> ${getUIText("hermesTitle")}`;
	}

	console.log("Modal UI language refreshed");
}

async function openUncloseaiEmbeddedModalNew() {
	try {
		// Load CryptoJS and initialize vault
		await ensureCryptoJS();
		if (UncloseVault.isAvailable()) {
			UncloseVault.init();
		}

		// Detect if PicoCSS is actually present on the page
		const hasPicoCSS = document.querySelector('link[href*="pico"]') !== null;

		// Load appropriate CSS based on actual PicoCSS presence
		const cssFile = hasPicoCSS
			? "uncloseai-modal-pico.css"
			: "uncloseai-modal-builtin.css";

		if (!document.querySelector(`link[href*="${cssFile}"]`)) {
			const link = document.createElement("link");
			link.rel = "stylesheet";
			link.href = `https://uncloseai.com/src/${cssFile}`;
			document.head.appendChild(link);
		}

		// Load highlight.js CSS for code block syntax highlighting
		if (!document.querySelector('link[href*="highlight"]')) {
			const hljsLink = document.createElement("link");
			hljsLink.rel = "stylesheet";
			hljsLink.href =
				"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.10.0/styles/a11y-dark.min.css";
			document.head.appendChild(hljsLink);
		}

		// Ensure ChunkFive font is loaded and text colors are enforced
		initializeChunkFiveFont();

		// Get theme colors
		const theme = detectCurrentTheme();
		const colors = getThemeColors(theme);

		// Set CSS custom properties for theme support
		const root = document.documentElement;
		root.style.setProperty(
			"--uncloseai-button-background",
			colors.buttonBackground,
		);
		root.style.setProperty("--uncloseai-button-hover", colors.buttonHover);
		root.style.setProperty("--uncloseai-button-border", colors.buttonBorder);
		root.style.setProperty("--uncloseai-primary-text", colors.primaryText);
		root.style.setProperty(
			"--uncloseai-action-background",
			colors.actionBackground,
		);
		root.style.setProperty("--uncloseai-action-hover", colors.actionHover);
		root.style.setProperty("--uncloseai-action-border", colors.actionBorder);
		root.style.setProperty("--uncloseai-action-text", colors.primaryText);

		const modal = document.createElement("dialog");
		modal.id = "uncloseai-embedded-modal";
		modal.setAttribute("data-theme", theme);
		// Force inline resets so host page dialog styles can't push content inward
		modal.style.cssText = "padding:0;margin:0;border:none;overflow:hidden;";

		// CSS handles all styling now - no inline styles needed
		// But we still need isMobile for some responsive text sizing
		const isMobile = window.innerWidth <= 768;

		// Simple container with grid layout
		const container = document.createElement("div");
		container.className = "uncloseai-modal-container";
		container.style.cssText = "width:100%;height:100%;box-sizing:border-box;";

		// Header - inline width:100% to beat host page <header> styles
		const header = document.createElement("header");
		header.className = "uncloseai-modal-header";
		header.style.cssText = "width:100%;max-width:none;box-sizing:border-box;";

		const titleContainer = document.createElement("div");
		titleContainer.className = "uncloseai-title-container";

		const title = document.createElement("h2");
		title.innerHTML =
			"<span style=\"font-family: 'ChunkFiveRegular', monospace;\">uncloseai.</span>";
		title.className = `uncloseai-modal-title ${isMobile ? "uncloseai-modal-title-mobile" : "uncloseai-modal-title-desktop"}`;

		const subtitle = document.createElement("div");
		const pageTitle = document.title || window.location.hostname;
		subtitle.innerHTML = `
		<div class="uncloseai-modal-subtitle">
			${getUIText("discussingPage")}: ${pageTitle}
		</div>
	`;

		titleContainer.appendChild(title);
		titleContainer.appendChild(subtitle);

		const closeBtn = document.createElement("button");
		closeBtn.textContent = "✕";
		closeBtn.className = "uncloseai-btn-close";
		// Close button handler will be set after settings panel is created

		// Add settings/menu button
		const menuBtn = document.createElement("button");
		menuBtn.textContent = "⚙️";
		menuBtn.className = "uncloseai-modal-settings-btn";

		const headerRight = document.createElement("div");
		headerRight.className = "uncloseai-flex-row";
		headerRight.appendChild(menuBtn);
		headerRight.appendChild(closeBtn);

		header.appendChild(titleContainer);
		header.appendChild(headerRight);

		// Chat area
		const chatArea = document.createElement("div");
		chatArea.className = "uncloseai-modal-chat-area";

		const chatBox = document.createElement("div");
		chatBox.id = "modal-chat-box";
		chatBox.className = "uncloseai-chat-box";
		chatArea.appendChild(chatBox);

		// Settings panel (collapsible)
		const settingsPanel = document.createElement("div");
		settingsPanel.className = "uncloseai-modal-settings";

		// Vault UI section
		const vaultSection = document.createElement("div");
		vaultSection.className = "uncloseai-section uncloseai-vault-section";
		vaultSection.style.gridColumn = "1 / -1"; // Full width
		vaultSection.style.marginBottom = "16px";
		vaultSection.style.padding = "12px";
		vaultSection.style.borderRadius = "8px";
		vaultSection.style.border = "1px solid var(--uncloseai-border-color, #ccc)";

		// Container for the rest of settings (will be hidden when vault locked)
		const settingsContent = document.createElement("div");
		settingsContent.className = "uncloseai-settings-content";

		// Helper to get vault value or localStorage fallback (for migration)
		function getVaultOrStorage(key, defaultValue = null) {
			if (UncloseVault.isAvailable() && UncloseVault.isUnlocked()) {
				return UncloseVault.get(key, defaultValue);
			}
			// Fallback for when vault not available
			const stored = localStorage.getItem(key);
			return stored !== null ? stored : defaultValue;
		}

		// Helper to set vault value
		function setVaultValue(key, value) {
			if (UncloseVault.isAvailable() && UncloseVault.isUnlocked()) {
				UncloseVault.set(key, value);
			} else {
				// If vault not unlocked, store temporarily (will be lost)
				console.warn("Vault locked - setting not persisted:", key);
			}
		}

		// Build vault UI based on current state
		function buildVaultUI() {
			vaultSection.innerHTML = "";

			if (!UncloseVault.isAvailable()) {
				// CryptoJS not loaded - settings work but won't persist across sessions
				vaultSection.style.display = "none";
				settingsContent.style.display = "grid";
				return;
			}

			if (UncloseVault.isUnlocked()) {
				// Vault unlocked - thin bar at top with logged in status and lock button
				vaultSection.style.cssText =
					"display: grid; grid-template-columns: 1fr auto; align-items: center; grid-column: 1 / -1; padding: 6px 12px; font-size: 0.85em;";
				const unlockedUI = document.createElement("span");
				unlockedUI.style.color = "#28a745";
				unlockedUI.textContent = `✓ ${getUIText("vaultLoggedIn")}`;

				const lockBtn = document.createElement("button");
				lockBtn.className = "uncloseai-btn-small";
				lockBtn.title = getUIText("vaultLockTooltip");
				lockBtn.textContent = `🔒 ${getUIText("vaultLock")}`;

				lockBtn.onclick = () => {
					UncloseVault.lock();
					// Clear decrypted chat from DOM
					chatBox.innerHTML = "";
					// Hide settings content and input
					settingsContent.style.display = "none";
					inputArea.style.display = "none";
					buildVaultUI();
					// Close settings panel after locking
					settingsOpen = false;
					applySettingsState();
					// Re-show the vault gate
					showVaultGate();
				};

				vaultSection.appendChild(unlockedUI);
				vaultSection.appendChild(lockBtn);
				settingsContent.style.display = "grid"; // Show settings when unlocked
			} else {
				// Vault locked or doesn't exist - show centered prompt using CSS grid
				vaultSection.style.display = "grid";
				vaultSection.style.placeContent = "center";
				vaultSection.style.height = "100%";
				vaultSection.style.minHeight = "360px";
				vaultSection.style.border = "none";
				vaultSection.style.padding = "16px";
				const hasVault = UncloseVault.hasVault();

				const promptUI = document.createElement("div");
				promptUI.className = "uncloseai-vault-card";
				promptUI.innerHTML = `
				<div class="uncloseai-vault-icon">${hasVault ? "\u{1F513}" : "\u{1F510}"}</div>
				<div class="uncloseai-vault-title">${getUIText("vaultGateTitle")}</div>
				<div class="uncloseai-vault-explanation">
					${hasVault ? getUIText("vaultWelcomeBack") : getUIText("vaultLine1")}
				</div>
				${!hasVault ? `<div class="uncloseai-vault-explanation">${getUIText("vaultLine2")}</div>` : ""}
				<input type="password" class="vault-password uncloseai-vault-input" placeholder="${getUIText("vaultPasswordPlaceholder")}">
				<button class="vault-submit-btn uncloseai-vault-submit">
					${getUIText("vaultUnlock")}
				</button>
				<div class="vault-error uncloseai-vault-error"></div>
			`;

				const passwordInput = promptUI.querySelector(".vault-password");
				const submitBtn = promptUI.querySelector(".vault-submit-btn");
				const errorDiv = promptUI.querySelector(".vault-error");

				submitBtn.onclick = () => {
					const password = passwordInput.value;
					// Check fresh vault state (not stale closure)
					const vaultExists = UncloseVault.hasVault();

					if (vaultExists) {
						// Unlock existing vault
						const result = UncloseVault.unlock(password);
						if (result.success) {
							buildVaultUI();
							refreshSettingsFromVault();
						} else {
							errorDiv.textContent = getUIText("vaultWrongPassword");
							errorDiv.style.display = "block";
							passwordInput.value = "";
							passwordInput.focus();
						}
					} else {
						// Create new vault
						if (password.length < 8) {
							errorDiv.textContent = getUIText("vaultPasswordTooShort");
							errorDiv.style.display = "block";
							return;
						}

						const result = UncloseVault.create(password);
						if (result.success) {
							migrateSettingsToVault();
							buildVaultUI();
						} else {
							errorDiv.textContent = result.error;
							errorDiv.style.display = "block";
						}
					}
				};

				// Allow Enter key to submit
				passwordInput.onkeydown = (e) => {
					if (e.key === "Enter") submitBtn.click();
				};

				vaultSection.appendChild(promptUI);
				settingsContent.style.display = "none"; // Hide settings until unlocked
			}
		}

		// Migrate existing localStorage settings to vault
		function migrateSettingsToVault() {
			if (!UncloseVault.isUnlocked()) return;

			const keysToMigrate = [
				"selectedModel",
				"selectedEndpoint",
				"selectedVoice",
				"useCustomAPI",
				"customBaseURL",
				"customAPIKey",
				"useUnsandbox",
				"unsandboxPublicKey",
				"unsandboxSecretKey",
				"hermesSettingsOpen",
				"uncloseai_language",
				"uncloseai_selected_voice",
				"uncloseai_tts_mode",
			];

			keysToMigrate.forEach((key) => {
				const value = localStorage.getItem(key);
				if (value !== null) {
					// Parse booleans
					let parsedValue = value;
					if (value === "true") parsedValue = true;
					else if (value === "false") parsedValue = false;

					UncloseVault.set(key, parsedValue);
					// Remove from plain localStorage after migration
					localStorage.removeItem(key);
				}
			});

			console.log("Settings migrated to vault");
		}

		// Refresh UI inputs from vault values
		function refreshSettingsFromVault() {
			// Model selection will be loaded from vault when loadModels is called
			// Voice selection will be loaded from vault when loadVoices is called
			// Language will be loaded from vault

			// Refresh API config
			if (customAPICheckbox) {
				customAPICheckbox.checked =
					getVaultOrStorage("useCustomAPI") === true ||
					getVaultOrStorage("useCustomAPI") === "true";
				apiConfigInputs.style.display = customAPICheckbox.checked
					? "block"
					: "none";
			}
			if (baseURLInput) {
				baseURLInput.value = getVaultOrStorage("customBaseURL", "");
			}
			if (apiKeyInput) {
				apiKeyInput.value = getVaultOrStorage("customAPIKey", "");
			}

			// Refresh unsandbox config
			if (unsandboxCheckbox) {
				unsandboxCheckbox.checked =
					getVaultOrStorage("useUnsandbox") === true ||
					getVaultOrStorage("useUnsandbox") === "true";
				unsandboxInputs.style.display = unsandboxCheckbox.checked
					? "block"
					: "none";
			}
			if (unsandboxPublicKeyInput) {
				unsandboxPublicKeyInput.value = getVaultOrStorage(
					"unsandboxPublicKey",
					"",
				);
			}
			if (unsandboxSecretKeyInput) {
				unsandboxSecretKeyInput.value = getVaultOrStorage(
					"unsandboxSecretKey",
					"",
				);
			}
		}

		// Model selection
		const modelSection = document.createElement("div");
		modelSection.className = "uncloseai-section";

		const modelSelect = document.createElement("select");
		modelSelect.id = "modal-model-selection";
		modelSelect.className = "uncloseai-modal-select";

		// Store models for selection handler
		let loadedModels = [];

		// Load models
		const loadModels = async () => {
			try {
				console.log("Loading models for Hermes modal...");
				const models = await fetchModelsFromEndpoints();
				console.log("Models loaded:", models);
				loadedModels = models; // Store for selection handler
				modelSelect.innerHTML = "";

				if (models && models.length > 0) {
					models.forEach((model) => {
						const option = document.createElement("option");
						option.value = model.uniqueId;
						option.textContent = `${model.endpointId} | ${model.modelName}`;
						modelSelect.appendChild(option);
					});

					// Load saved model from vault or use current selection
					const savedModel = getVaultOrStorage("selectedModel");
					const savedEndpoint = getVaultOrStorage("selectedEndpoint");
					const currentModel = getSelectedModel();

					if (savedModel && savedEndpoint) {
						const savedOption = Array.from(modelSelect.options).find(
							(opt) =>
								opt.textContent.includes(savedModel) &&
								opt.textContent.includes(savedEndpoint),
						);
						if (savedOption) {
							modelSelect.value = savedOption.value;
							console.log(
								"Restored saved model:",
								savedModel,
								"from endpoint:",
								savedEndpoint,
							);
						}
					} else if (currentModel) {
						const currentOption = Array.from(modelSelect.options).find((opt) =>
							opt.textContent.includes(currentModel),
						);
						if (currentOption) {
							modelSelect.value = currentOption.value;
						}
					}
				} else {
					const option = document.createElement("option");
					option.textContent = "No models available";
					option.disabled = true;
					modelSelect.appendChild(option);
				}
			} catch (error) {
				console.error("Failed to load models:", error);
				const option = document.createElement("option");
				option.textContent = "Error loading models";
				option.disabled = true;
				modelSelect.appendChild(option);
			}
		};

		// Handle model selection changes
		modelSelect.onchange = () => {
			const selectedUniqueId = modelSelect.value;
			const selectedModel = loadedModels.find(
				(model) => model.uniqueId === selectedUniqueId,
			);
			if (selectedModel) {
				// Update the model selection in vault
				setVaultValue("selectedModel", selectedModel.modelName);
				setVaultValue("selectedEndpoint", selectedModel.endpointId);
				console.log("Model changed to:", selectedModel);
			}
		};

		modelSection.appendChild(modelSelect);

		// Voice selection for TTS
		const voiceSection = document.createElement("div");
		voiceSection.className = "uncloseai-section";

		const voiceSelect = document.createElement("select");
		voiceSelect.id = "hermes-voice-select";
		voiceSelect.className = "uncloseai-modal-select";

		// Store loaded voices count
		let loadedVoicesCount = 0;

		// Load voices dynamically from API
		const loadVoices = async () => {
			const { VOICES_API_URL } = await import("./config.js");
			const response = await fetch(VOICES_API_URL);

			if (!response.ok) {
				throw new Error(`HTTP error! status: ${response.status}`);
			}

			const data = await response.json();
			const models = data.data || [];

			if (models.length === 0) {
				throw new Error("No models in API response");
			}

			voiceSelect.innerHTML = ""; // Clear existing options

			// Count total voices across all models
			loadedVoicesCount = models.reduce(
				(sum, model) => sum + (model.voices?.length || 0),
				0,
			);

			// Add options grouped by model
			models.forEach((model) => {
				const voices = model.voices || [];
				if (voices.length === 0) return;

				const optgroup = document.createElement("optgroup");
				optgroup.label = model.id;

				voices.forEach((voice) => {
					const option = document.createElement("option");
					option.value = `${model.id}:${voice}`; // Store model:voice format
					option.textContent = voice;
					optgroup.appendChild(option);
				});

				voiceSelect.appendChild(optgroup);
			});

			// Load saved voice from vault or default to first voice
			const savedVoice = getVaultOrStorage("selectedVoice");
			if (
				savedVoice &&
				voiceSelect.querySelector(`option[value="${savedVoice}"]`)
			) {
				voiceSelect.value = savedVoice;
			}

			console.log(
				"Voices loaded:",
				loadedVoicesCount,
				"voices from",
				models.length,
				"models",
			);
		};

		// Save voice selection to vault when changed
		voiceSelect.onchange = () => {
			setVaultValue("selectedVoice", voiceSelect.value);
			console.log("Voice changed to:", voiceSelect.value);
		};

		voiceSection.appendChild(voiceSelect);

		// Load voices asynchronously
		loadVoices();

		// Language preference section
		const languageSection = document.createElement("div");
		languageSection.className = "uncloseai-section";

		// Create language selector
		const { SUPPORTED_LANGUAGES, NATIVE_LANGUAGE_NAMES } = await import(
			"./translation.js"
		);
		const { normalizeLanguageCode } = await import("./config.js");

		// Check if language is forced by embed config
		const rawForcedLang =
			typeof window !== "undefined" && window.UNCLOSEAI_LANGUAGE
				? window.UNCLOSEAI_LANGUAGE
				: null;
		const forcedLang = normalizeLanguageCode(rawForcedLang);
		const currentLang =
			rawForcedLang && forcedLang ? forcedLang : getUserLanguagePreference();

		const languageSelect = document.createElement("select");
		languageSelect.id = "hermes-language-select";
		languageSelect.className = "uncloseai-modal-select";

		// If language is forced, disable the selector
		if (rawForcedLang) {
			languageSelect.disabled = true;
			languageSelect.title = "Language is set by this site";
		}

		// Add options for each supported language
		Object.entries(SUPPORTED_LANGUAGES).forEach(([code, englishName]) => {
			const option = document.createElement("option");
			option.value = code;
			const nativeName = NATIVE_LANGUAGE_NAMES[code];
			option.textContent = `${nativeName} (${englishName})`;

			if (code === currentLang) {
				option.selected = true;
			}

			languageSelect.appendChild(option);
		});

		// Handle language change (only if not forced)
		if (!rawForcedLang) {
			languageSelect.onchange = () => {
				const newLang = languageSelect.value;
				setUserLanguagePreference(newLang);

				// Show confirmation
				const selectedOption =
					languageSelect.options[languageSelect.selectedIndex];
				console.log(`Language changed to: ${selectedOption.textContent}`);

				// Refresh all UI text in the modal
				refreshModalUI();

				// Notify user to refresh for full effect
				setTimeout(() => {
					const langName = SUPPORTED_LANGUAGES[newLang];
					alert(getUIText("languageChanged", { lang: langName }));
				}, 100);
			};
		}

		languageSection.appendChild(languageSelect);

		// API Configuration section
		const apiConfigSection = document.createElement("div");
		apiConfigSection.className = "uncloseai-section";

		// Toggle for custom API
		const customAPIToggle = document.createElement("div");
		customAPIToggle.className = "uncloseai-toggle-container";

		const customAPICheckbox = document.createElement("input");
		customAPICheckbox.type = "checkbox";
		customAPICheckbox.id = "custom-api-toggle";
		customAPICheckbox.checked =
			getVaultOrStorage("useCustomAPI") === true ||
			getVaultOrStorage("useCustomAPI") === "true";

		const customAPIToggleLabel = document.createElement("label");
		customAPIToggleLabel.htmlFor = "custom-api-toggle";
		customAPIToggleLabel.textContent = getUIText("useCustomAPI");
		customAPIToggleLabel.className = "uncloseai-toggle-label";

		customAPIToggle.appendChild(customAPICheckbox);
		customAPIToggle.appendChild(customAPIToggleLabel);

		// Base URL input
		const baseURLContainer = document.createElement("div");
		baseURLContainer.className = "uncloseai-input-container";

		const baseURLInput = document.createElement("input");
		baseURLInput.type = "text";
		baseURLInput.placeholder = "https://api.openai.com/v1";
		baseURLInput.value = getVaultOrStorage("customBaseURL", "");
		baseURLInput.className = "uncloseai-input";

		baseURLContainer.appendChild(baseURLInput);

		// API Key input
		const apiKeyContainer = document.createElement("div");
		apiKeyContainer.className = "uncloseai-input-container";

		const apiKeyInput = document.createElement("input");
		apiKeyInput.type = "password";
		apiKeyInput.placeholder = "API Key";
		apiKeyInput.value = getVaultOrStorage("customAPIKey", "");
		apiKeyInput.className = "uncloseai-input";

		apiKeyContainer.appendChild(apiKeyInput);

		// API Config container for inputs
		const apiConfigInputs = document.createElement("div");
		apiConfigInputs.className = "uncloseai-api-inputs";
		apiConfigInputs.style.display = customAPICheckbox.checked
			? "block"
			: "none";
		apiConfigInputs.appendChild(baseURLContainer);
		apiConfigInputs.appendChild(apiKeyContainer);

		// Event handlers
		customAPICheckbox.onchange = () => {
			const useCustom = customAPICheckbox.checked;
			setVaultValue("useCustomAPI", useCustom);
			apiConfigInputs.style.display = useCustom ? "block" : "none";
		};

		baseURLInput.onchange = () => {
			setVaultValue("customBaseURL", baseURLInput.value);
		};

		apiKeyInput.onchange = () => {
			setVaultValue("customAPIKey", apiKeyInput.value);
		};

		apiConfigSection.appendChild(customAPIToggle);
		apiConfigSection.appendChild(apiConfigInputs);

		// Unsandbox Code Execution section
		const unsandboxSection = document.createElement("div");
		unsandboxSection.className = "uncloseai-section";

		// Toggle for unsandbox API keys
		const unsandboxToggle = document.createElement("div");
		unsandboxToggle.className = "uncloseai-toggle-container";

		const unsandboxCheckbox = document.createElement("input");
		unsandboxCheckbox.type = "checkbox";
		unsandboxCheckbox.id = "unsandbox-toggle";
		unsandboxCheckbox.checked =
			getVaultOrStorage("useUnsandbox") === true ||
			getVaultOrStorage("useUnsandbox") === "true";

		const unsandboxToggleLabel = document.createElement("label");
		unsandboxToggleLabel.htmlFor = "unsandbox-toggle";
		unsandboxToggleLabel.textContent = getUIText("useUnsandbox");
		unsandboxToggleLabel.className = "uncloseai-toggle-label";

		unsandboxToggle.appendChild(unsandboxCheckbox);
		unsandboxToggle.appendChild(unsandboxToggleLabel);

		// Public Key input
		const unsandboxPublicKeyContainer = document.createElement("div");
		unsandboxPublicKeyContainer.className = "uncloseai-input-container";

		const unsandboxPublicKeyInput = document.createElement("input");
		unsandboxPublicKeyInput.type = "text";
		unsandboxPublicKeyInput.placeholder = getUIText("unsandboxPublicKey");
		unsandboxPublicKeyInput.value = getVaultOrStorage("unsandboxPublicKey", "");
		unsandboxPublicKeyInput.className = "uncloseai-input";

		unsandboxPublicKeyContainer.appendChild(unsandboxPublicKeyInput);

		// Secret Key input
		const unsandboxSecretKeyContainer = document.createElement("div");
		unsandboxSecretKeyContainer.className = "uncloseai-input-container";

		const unsandboxSecretKeyInput = document.createElement("input");
		unsandboxSecretKeyInput.type = "password";
		unsandboxSecretKeyInput.placeholder = getUIText("unsandboxSecretKey");
		unsandboxSecretKeyInput.value = getVaultOrStorage("unsandboxSecretKey", "");
		unsandboxSecretKeyInput.className = "uncloseai-input";

		unsandboxSecretKeyContainer.appendChild(unsandboxSecretKeyInput);

		// Unsandbox inputs container
		const unsandboxInputs = document.createElement("div");
		unsandboxInputs.className = "uncloseai-api-inputs";
		unsandboxInputs.style.display = unsandboxCheckbox.checked
			? "block"
			: "none";
		unsandboxInputs.appendChild(unsandboxPublicKeyContainer);
		unsandboxInputs.appendChild(unsandboxSecretKeyContainer);

		// Event handlers for unsandbox
		unsandboxCheckbox.onchange = () => {
			const useUnsandbox = unsandboxCheckbox.checked;
			setVaultValue("useUnsandbox", useUnsandbox);
			unsandboxInputs.style.display = useUnsandbox ? "block" : "none";
		};

		unsandboxPublicKeyInput.onchange = () => {
			setVaultValue("unsandboxPublicKey", unsandboxPublicKeyInput.value);
		};

		unsandboxSecretKeyInput.onchange = () => {
			setVaultValue("unsandboxSecretKey", unsandboxSecretKeyInput.value);
		};

		unsandboxSection.appendChild(unsandboxToggle);
		unsandboxSection.appendChild(unsandboxInputs);

		// Action buttons
		const actionsSection = document.createElement("div");
		actionsSection.className = "uncloseai-section";

		const actionsGrid = document.createElement("div");
		actionsGrid.className = "uncloseai-grid-actions";
		actionsGrid.style.cssText =
			"display: grid; grid-template-columns: 1fr 1fr; gap: 8px; width: 100%;";

		const actions = [
			{
				text: getUIText("refreshModels"),
				action: async () => {
					const button = event.target;
					const originalText = button.textContent;
					button.textContent = "🔄 Loading...";
					button.disabled = true;

					// Use allSettled to handle partial failures
					const [modelsResult, voicesResult] = await Promise.allSettled([
						loadModels(),
						loadVoices(),
					]);

					const modelsOk = modelsResult.status === "fulfilled";
					const voicesOk = voicesResult.status === "fulfilled";

					// Build status message
					const statusParts = [];
					if (modelsOk) {
						const modelCount = modelSelect.options.length;
						statusParts.push(`✅ ${modelCount} models`);
					} else {
						const errMsg = modelsResult.reason?.message || "error";
						statusParts.push(`❌ Models: ${errMsg}`);
					}

					if (voicesOk) {
						statusParts.push(`✅ ${loadedVoicesCount} voices`);
					} else {
						const errMsg = voicesResult.reason?.message || "error";
						statusParts.push(`❌ TTS: ${errMsg}`);
					}

					button.textContent = statusParts.join(", ");
					setTimeout(() => {
						button.textContent = originalText;
						button.disabled = false;
					}, 3000);
				},
			},
			{
				text: getUIText("clearChat"),
				action: async () => {
					if (confirm(getUIText("clearChatConfirm"))) {
						chatBox.innerHTML = "";
						await clearConversationHistory();

						// Also clear the chat history in the chat.js module
						const currentHistory = await getChatHistory();
						const systemMsg = currentHistory.find(
							(msg) => msg.role === "system",
						);
						const newHistory = systemMsg ? [systemMsg] : [];
						await updateChatHistory(newHistory);
						console.log("Chat history cleared, reset to system message only");

						// Re-add intro message
						await addIntroMessage();
					}
				},
			},
		];

		actions.forEach(({ text, action }) => {
			const btn = document.createElement("button");
			btn.textContent = text;
			btn.className = "uncloseai-btn-control";
			btn.onclick = action;
			actionsGrid.appendChild(btn);
		});

		actionsSection.appendChild(actionsGrid);

		// Create left and right columns
		const leftColumn = document.createElement("div");
		leftColumn.className = "uncloseai-settings-column";
		leftColumn.appendChild(modelSection);
		leftColumn.appendChild(voiceSection);
		leftColumn.appendChild(languageSection);

		const rightColumn = document.createElement("div");
		rightColumn.className = "uncloseai-settings-column";
		rightColumn.appendChild(apiConfigSection);
		rightColumn.appendChild(unsandboxSection);

		// Quick actions span both columns
		actionsSection.className = "uncloseai-section uncloseai-actions-full-width";
		actionsSection.style.cssText = "grid-column: 1 / -1; width: 100%;";

		// Wrap settings in settingsContent container (shown/hidden based on vault state)
		settingsContent.appendChild(actionsSection);
		settingsContent.appendChild(leftColumn);
		settingsContent.appendChild(rightColumn);
		// Two-column grid layout, display controlled by buildVaultUI
		settingsContent.style.gridTemplateColumns = "1fr 1fr";
		settingsContent.style.gap = "12px";
		settingsContent.style.alignContent = "start";
		// NOTE: display is set by buildVaultUI() - do not set here

		// Columns should align content to top and use full width
		leftColumn.style.cssText =
			"display: grid; gap: 8px; align-content: start; width: 100%;";
		rightColumn.style.cssText =
			"display: grid; gap: 8px; align-content: start; width: 100%;";

		// Add vault section first, then settings content
		// Both must span full width since parent settingsPanel uses 2-column grid (from CSS)
		vaultSection.style.gridColumn = "1 / -1";
		settingsContent.style.gridColumn = "1 / -1";
		settingsPanel.appendChild(vaultSection);
		settingsPanel.appendChild(settingsContent);

		// Initialize vault UI (must be after settingsContent is set up)
		buildVaultUI();

		// Load and save settings panel state
		let settingsOpen =
			getVaultOrStorage("hermesSettingsOpen") === true ||
			getVaultOrStorage("hermesSettingsOpen") === "true";

		function applySettingsState() {
			settingsPanel.classList.toggle("open", settingsOpen);
			chatArea.style.display = settingsOpen ? "none" : "";
			if (controls) controls.style.display = settingsOpen ? "none" : "";
		}

		menuBtn.onclick = () => {
			settingsOpen = !settingsOpen;
			applySettingsState();
			setVaultValue("hermesSettingsOpen", settingsOpen);
		};

		// Set close button handler now that settings panel is available
		closeBtn.onclick = () => {
			// If settings panel is open, close it first
			if (settingsOpen) {
				settingsOpen = false;
				applySettingsState();
				setVaultValue("hermesSettingsOpen", settingsOpen);
				return; // Don't close modal yet
			}

			// Settings closed or not open, close the modal
			modal.close();
			document.body.removeChild(modal);
			uncloseaiEmbeddedModalOpen = false;
		};

		// Quick action buttons
		const controls = document.createElement("div");
		controls.className = "uncloseai-modal-controls";

		// Apply initial settings state now that controls exists
		if (settingsOpen) {
			applySettingsState();
		}

		// HTML to Markdown converter function
		function htmlToMarkdown(html) {
			// Create a temporary element to parse HTML
			const temp = document.createElement("div");
			temp.innerHTML = html;

			// Remove script and style elements
			temp.querySelectorAll("script, style, noscript").forEach((el) => {
				el.remove();
			});

			function processNode(node) {
				if (node.nodeType === Node.TEXT_NODE) {
					return node.textContent.trim();
				}

				if (node.nodeType !== Node.ELEMENT_NODE) return "";

				const tag = node.tagName.toLowerCase();
				const children = Array.from(node.childNodes).map(processNode).join("");

				switch (tag) {
					case "h1":
						return `# ${children}\n\n`;
					case "h2":
						return `## ${children}\n\n`;
					case "h3":
						return `### ${children}\n\n`;
					case "h4":
						return `#### ${children}\n\n`;
					case "h5":
						return `##### ${children}\n\n`;
					case "h6":
						return `###### ${children}\n\n`;
					case "p":
						return `${children}\n\n`;
					case "br":
						return "\n";
					case "strong":
					case "b":
						return `**${children}**`;
					case "em":
					case "i":
						return `*${children}*`;
					case "code":
						return `\`${children}\``;
					case "pre":
						return `\`\`\`\n${children}\n\`\`\`\n\n`;
					case "a": {
						const href = node.getAttribute("href");
						return href ? `[${children}](${href})` : children;
					}
					case "img": {
						const src = node.getAttribute("src");
						const alt = node.getAttribute("alt") || "";
						return src ? `![${alt}](${src})` : "";
					}
					case "ul":
					case "ol":
						return `${children}\n`;
					case "li":
						return `- ${children}\n`;
					case "blockquote":
						return `> ${children}\n\n`;
					default:
						return children;
				}
			}

			return processNode(temp).trim();
		}

		let readPageAudio = null;
		let isReadingPage = false;
		let readPageContainer = null;

		const controlActions = [
			{
				emoji: "📖",
				tooltip: getUIText("readPage"),
				action: async (button) => {
					// If already playing, pause
					if (readPageAudio && !readPageAudio.paused) {
						readPageAudio.pause();
						return;
					}

					// If paused, resume
					if (readPageAudio?.paused && readPageAudio.currentTime > 0) {
						readPageAudio.play();
						return;
					}

					// Prevent multiple simultaneous requests
					if (isReadingPage) return;

					// Start new reading
					button.title = getUIText("processingContent");
					button.textContent = "⏳";
					button.disabled = true;
					isReadingPage = true;

					try {
						// Get page content
						const { extractWebpageContent } = await import("./content.js");
						const pageContent = await extractWebpageContent();

						// Generate TTS
						const { speakText } = await import("./tts.js");
						const result = await speakText(pageContent, "alloy", 1.0);
						readPageAudio = result.audio;

						// Set up audio event handlers with tooltips
						readPageAudio.onplay = () => {
							button.textContent = "⏸️";
							button.title = getUIText("readingPageClickToPause");
							isReadingPage = true;
						};

						readPageAudio.onpause = () => {
							button.textContent = "▶️";
							button.title = getUIText("pausedClickToResume");
						};

						readPageAudio.onended = () => {
							button.textContent = "📖";
							button.title = getUIText("readPage");
							isReadingPage = false;
							// Keep readPageAudio reference for download
							// Keep download button visible
						};

						// Add download button next to the read button
						if (!readPageContainer) {
							readPageContainer = document.createElement("div");
							readPageContainer.className = "uncloseai-read-page-container";

							// Add download button
							const downloadBtn = document.createElement("button");
							downloadBtn.textContent = "💾";
							downloadBtn.title = getUIText("downloadPageAudio");
							downloadBtn.className = "uncloseai-btn-primary";
							downloadBtn.onclick = () => {
								if (readPageAudio) {
									const url = readPageAudio.src;
									const a = document.createElement("a");
									a.href = url;
									a.download = "page-audio.mp3";
									document.body.appendChild(a);
									a.click();
									document.body.removeChild(a);
								}
							};

							// Insert container after the read button and add download button
							const parent = button.parentElement;
							parent.insertBefore(readPageContainer, button.nextSibling);
							readPageContainer.appendChild(downloadBtn);
						}

						// Auto-play the generated audio
						try {
							await readPageAudio.play();
						} catch (_playError) {
							button.title = getUIText("readPage");
							isReadingPage = false;
						}
					} catch (error) {
						alert(getUIText("failedToReadPage", { error: error.message }));
						button.title = getUIText("readPage");
						isReadingPage = false;
					} finally {
						button.disabled = false;
					}
				},
			},
			{
				emoji: "🔊",
				tooltip: getUIText("ttsAnything"),
				action: async (_btn) => {
					if (typeof window.openTTSModal === "function") {
						window.openTTSModal();
					} else {
						// Fallback: dynamically import and call
						try {
							const { openTTSModal } = await import("./tts-modal.js");
							openTTSModal();
						} catch (error) {
							console.error("Failed to open TTS modal:", error);
						}
					}
				},
			},
			{
				emoji: "🌐",
				tooltip: getUIText("translationModal"),
				action: async (_btn) => {
					if (typeof window.openTranslateModal === "function") {
						window.openTranslateModal();
					} else {
						// Fallback: dynamically import and call
						try {
							const { openTranslateModal } = await import(
								"./translate-modal.js"
							);
							openTranslateModal();
						} catch (error) {
							console.error("Failed to open translate modal:", error);
						}
					}
				},
			},
			{
				emoji: "📋",
				tooltip: getUIText("fullChatRaw"),
				action: async () => {
					try {
						const { getChatHistory } = await import("./chat.js");
						const history = await getChatHistory();
						let rawContent = "";
						history.forEach((msg) => {
							if (msg.role === "user") {
								rawContent += `**You:** ${msg.content}\n\n`;
							} else if (msg.role === "assistant") {
								rawContent += `**AI:** ${msg.content}\n\n`;
							}
						});
						await navigator.clipboard.writeText(rawContent);
						alert(getUIText("fullChatCopied"));
					} catch (error) {
						alert(getUIText("failedToCopy", { error: error.message }));
					}
				},
			},
			{
				emoji: "📄",
				tooltip: getUIText("fullChatHTML"),
				action: async () => {
					try {
						const { getChatHistory } = await import("./chat.js");
						const history = await getChatHistory();
						let htmlContent =
							'<div style="font-family: system-ui, -apple-system, sans-serif;">';
						history.forEach((msg) => {
							if (msg.role === "user") {
								htmlContent += `<div style="margin-bottom: 16px;"><strong>You:</strong><br>${marked.parse(msg.content)}</div>`;
							} else if (msg.role === "assistant") {
								htmlContent += `<div style="margin-bottom: 16px;"><strong>AI:</strong><br>${marked.parse(msg.content)}</div>`;
							}
						});
						htmlContent += "</div>";
						await navigator.clipboard.writeText(htmlContent);
						alert(getUIText("fullChatHTMLCopied"));
					} catch (error) {
						alert(getUIText("failedToCopy", { error: error.message }));
					}
				},
			},
			{
				emoji: "📝",
				tooltip: getUIText("fullPageRaw"),
				action: async () => {
					try {
						// Get the entire page HTML
						const pageHtml = document.documentElement.outerHTML;
						// Convert to markdown
						const markdown = htmlToMarkdown(pageHtml);
						await navigator.clipboard.writeText(markdown);
						alert(getUIText("fullPageCopied"));
					} catch (error) {
						alert(getUIText("failedToCopyPage", { error: error.message }));
					}
				},
			},
		];

		controlActions.forEach(({ emoji, tooltip, action }) => {
			const btn = document.createElement("button");
			btn.textContent = emoji;
			btn.title = tooltip;
			btn.className = "uncloseai-btn-primary emoji-only";
			btn.onclick = () => action(btn);
			controls.appendChild(btn);
		});

		// Assemble modal structure
		container.appendChild(header);
		container.appendChild(settingsPanel);
		container.appendChild(chatArea);
		container.appendChild(controls);

		// Input area
		const inputArea = document.createElement("div");
		inputArea.className = "uncloseai-modal-input-area";

		const input = document.createElement("textarea");
		input.id = "modal-user-input";
		input.placeholder = getUIText("typePlaceholder");
		input.className = "uncloseai-modal-input";

		// Auto-resize textarea
		input.oninput = () => {
			input.style.height = "auto";
			input.style.height = `${Math.min(input.scrollHeight, 120)}px`;
		};

		const sendBtn = document.createElement("button");
		sendBtn.textContent = "→";
		sendBtn.className = "uncloseai-modal-send-btn";

		// Handle message sending
		const sendMessageHandler = async () => {
			const message = input.value.trim();
			if (!message) return;

			input.value = "";
			input.style.height = "44px";

			// Add user message
			const userMsg = document.createElement("div");
			userMsg.className = "user-message";

			// Add message text and actions inside the bubble
			const messageText = document.createElement("div");
			messageText.textContent = message;
			messageText.className = "message-text";

			const userMessageActions = document.createElement("div");
			userMessageActions.className = "uncloseai-message-actions";

			const userTtsBtn = document.createElement("button");
			userTtsBtn.textContent = "🔊";
			userTtsBtn.title = getUIText("playText");
			userTtsBtn.className = "uncloseai-btn-small";

			// Store audio for pause/resume functionality
			let userAudio = null;
			let _isPlaying = false;

			userTtsBtn.onclick = async () => {
				const modalVoiceSelect = document.getElementById("hermes-voice-select");
				const selectedVoice = modalVoiceSelect?.value || "tts-1:alloy";

				// If audio is already playing, pause it
				if (userAudio && !userAudio.paused) {
					userAudio.pause();
					userTtsBtn.textContent = "🔊";
					_isPlaying = false;
					return;
				}

				// If audio exists and is paused, resume it
				if (userAudio?.paused && userAudio.currentTime > 0) {
					userAudio.play();
					userTtsBtn.textContent = "⏸️";
					_isPlaying = true;
					return;
				}

				// Generate new audio
				const originalText = userTtsBtn.textContent;
				const originalTitle = userTtsBtn.title;
				userTtsBtn.textContent = "⏳";
				userTtsBtn.title = getUIText("processingContent");
				userTtsBtn.disabled = true;

				try {
					const result = await speakChatText(message, selectedVoice, 1.0);
					userAudio = result.audio;

					// Show and set up the download button
					const downloadBtn = userMessageActions.querySelector(
						".uncloseai-download-btn",
					);
					if (downloadBtn) {
						downloadBtn.style.display = ""; // Show the button
						downloadBtn.onclick = async () => {
							try {
								const { generateTitleForTTS } = await import("./tts.js");
								const filename = await generateTitleForTTS(message);
								const a = document.createElement("a");
								a.href = result.blobUrl;
								a.download = `${filename}.mp3`;
								a.click();
							} catch (error) {
								console.error("Error generating filename:", error);
								const a = document.createElement("a");
								a.href = result.blobUrl;
								a.download = "user-message.mp3";
								a.click();
							}
						};
					}

					// Set up audio event handlers
					userAudio.onplay = () => {
						userTtsBtn.textContent = "⏸️";
						userTtsBtn.title = getUIText("pausedClickToResume");
						_isPlaying = true;
					};

					userAudio.onpause = () => {
						userTtsBtn.textContent = "🔊";
						userTtsBtn.title = getUIText("playText");
						_isPlaying = false;
					};

					userAudio.onended = () => {
						userTtsBtn.textContent = "🔊";
						userTtsBtn.title = getUIText("playText");
						_isPlaying = false;
						userAudio = null;
					};

					// Auto-play the generated audio
					try {
						await userAudio.play();
					} catch (_playError) {
						userTtsBtn.textContent = "🔊";
					}
				} catch (error) {
					alert(error.message);
					userTtsBtn.textContent = originalText;
					userTtsBtn.title = originalTitle;
				} finally {
					userTtsBtn.disabled = false;
				}
			};

			const userDeleteBtn = document.createElement("button");
			userDeleteBtn.textContent = "🗑️";
			userDeleteBtn.title = getUIText("deleteMessage");
			userDeleteBtn.className = "uncloseai-btn-small";
			userDeleteBtn.onclick = async () => {
				// Remove from chat history and localStorage
				const { loadConversationHistory, saveConversationHistory } =
					await import("./storage.js");
				const { updateChatHistory } = await import("./chat.js");

				const currentHistory = await loadConversationHistory();
				const updatedHistory = currentHistory.filter(
					(msg) => !(msg.role === "user" && msg.content === message),
				);

				// Update both localStorage and chat.js module
				await saveConversationHistory(updatedHistory);
				await updateChatHistory(updatedHistory);

				userMsg.remove();
			};

			userMessageActions.appendChild(userTtsBtn);

			// Add download button initially (hidden until audio is generated)
			const userDownloadBtn = document.createElement("button");
			userDownloadBtn.textContent = "💾";
			userDownloadBtn.title = getUIText("downloadChatAudio");
			userDownloadBtn.className = "uncloseai-btn-small uncloseai-download-btn";
			userDownloadBtn.style.display = "none"; // Hidden initially
			userMessageActions.appendChild(userDownloadBtn);

			userMessageActions.appendChild(userDeleteBtn);
			userMsg.appendChild(messageText);
			userMsg.appendChild(userMessageActions);
			chatBox.appendChild(userMsg);

			// Add AI response placeholder
			const aiMsg = document.createElement("div");
			aiMsg.className = "ai-message";
			aiMsg.innerHTML = "<em>Thinking...</em>";
			chatBox.appendChild(aiMsg);

			chatArea.scrollTop = chatArea.scrollHeight;

			try {
				let response = "";
				for await (const chunk of sendMessage(message)) {
					response += chunk;
					aiMsg.innerHTML = marked.parse(response);
				}

				// Streaming is complete - now add final processing
				aiMsg.innerHTML = marked.parse(response);

				// Add syntax highlighting to all code blocks
				aiMsg.querySelectorAll("pre code").forEach((block) => {
					hljs.highlightElement(block);
				});

				// Add copy buttons after highlighting
				addCodeBlockCopyButtons(aiMsg);

				// Add the AI response to chat history manually since sendMessage generator doesn't do it
				const { getChatHistory, updateChatHistory } = await import("./chat.js");
				const currentHistory = await getChatHistory();
				currentHistory.push({ role: "assistant", content: response });
				await updateChatHistory(currentHistory);

				// Save conversation history after successful response
				await saveConversationHistory(currentHistory);
				console.log(
					"Conversation history saved:",
					currentHistory.length,
					"messages",
				);
				console.log(
					"Saved history content:",
					currentHistory.map((msg) => ({
						role: msg.role,
						content: `${msg.content.substring(0, 50)}...`,
					})),
				);

				// Add TTS and delete buttons to AI message
				const messageActions = document.createElement("div");
				messageActions.className = "uncloseai-message-actions";

				const ttsBtn = document.createElement("button");
				ttsBtn.textContent = "🔊";
				ttsBtn.title = getUIText("playText");
				ttsBtn.className = "uncloseai-btn-small";
				// Store audio for pause/resume functionality
				let currentAudio = null;

				ttsBtn.onclick = async () => {
					// Find voice selection from the modal by ID
					const modalVoiceSelect = document.getElementById(
						"hermes-voice-select",
					);
					const selectedVoice = modalVoiceSelect?.value || "tts-1:alloy";

					// If audio is already playing, pause it
					if (currentAudio && !currentAudio.paused) {
						currentAudio.pause();
						ttsBtn.textContent = "🔊";
						console.log("🔊 CHAT TTS: Paused");
						return;
					}

					// If audio exists and is paused, resume it
					if (currentAudio?.paused && currentAudio.currentTime > 0) {
						currentAudio.play();
						ttsBtn.textContent = "⏸️";
						console.log("🔊 CHAT TTS: Resumed");
						return;
					}

					// Generate new audio
					console.log("🔊 CHAT TTS: Generating new audio");
					const originalText = ttsBtn.textContent;
					const originalTitle = ttsBtn.title;
					ttsBtn.textContent = "⏳";
					ttsBtn.title = getUIText("processingContent");
					ttsBtn.disabled = true;

					try {
						const result = await speakChatText(response, selectedVoice, 1.0);
						currentAudio = result.audio;

						// Show and set up the download button
						const downloadBtn = messageActions.querySelector(
							".uncloseai-download-btn",
						);
						if (downloadBtn) {
							downloadBtn.style.display = ""; // Show the button
							downloadBtn.onclick = async () => {
								try {
									const { generateTitleForTTS } = await import("./tts.js");
									const filename = await generateTitleForTTS(response);
									const a = document.createElement("a");
									a.href = result.blobUrl;
									a.download = `${filename}.mp3`;
									a.click();
								} catch (error) {
									console.error("Error generating filename:", error);
									const a = document.createElement("a");
									a.href = result.blobUrl;
									a.download = "ai-response.mp3";
									a.click();
								}
							};
						}

						// Set up audio event handlers
						currentAudio.onplay = () => {
							ttsBtn.textContent = "⏸️";
							ttsBtn.title = getUIText("pausedClickToResume");
						};

						currentAudio.onpause = () => {
							ttsBtn.textContent = "🔊";
							ttsBtn.title = getUIText("playText");
						};

						currentAudio.onended = () => {
							ttsBtn.textContent = "🔊";
							ttsBtn.title = getUIText("playText");
							currentAudio = null;
						};

						// Auto-play the generated audio
						try {
							await currentAudio.play();
							console.log("🔊 CHAT TTS: Playing new audio");
						} catch (playError) {
							console.log("🔊 CHAT TTS: Auto-play blocked:", playError.message);
							ttsBtn.textContent = "🔊";
						}
					} catch (error) {
						console.error("🔊 CHAT TTS: Failed with error:", error);
						alert(error.message);
						ttsBtn.textContent = originalText;
						ttsBtn.title = originalTitle;
					} finally {
						ttsBtn.disabled = false;
					}
				};

				const deleteBtn = document.createElement("button");
				deleteBtn.textContent = "🗑️";
				deleteBtn.title = getUIText("deleteMessage");
				deleteBtn.className = "uncloseai-btn-small";
				deleteBtn.onclick = async () => {
					// Remove both user and AI messages from history and localStorage
					const { loadConversationHistory, saveConversationHistory } =
						await import("./storage.js");
					const { updateChatHistory } = await import("./chat.js");

					const currentHistory = await loadConversationHistory();
					const updatedHistory = currentHistory.filter(
						(msg) =>
							!(
								(msg.role === "user" && msg.content === message) ||
								(msg.role === "assistant" && msg.content === response)
							),
					);

					// Update both localStorage and chat.js module
					await saveConversationHistory(updatedHistory);
					await updateChatHistory(updatedHistory);

					userMsg.remove();
					aiMsg.remove();
				};

				// Copy Raw (Markdown) button
				const copyRawBtn = document.createElement("button");
				copyRawBtn.textContent = "📋";
				copyRawBtn.title = getUIText("copyRawMarkdown");
				copyRawBtn.className = "uncloseai-btn-small";
				copyRawBtn.onclick = async () => {
					try {
						await navigator.clipboard.writeText(response);
						const originalText = copyRawBtn.textContent;
						copyRawBtn.textContent = "✓";
						setTimeout(() => {
							copyRawBtn.textContent = originalText;
						}, 1000);
					} catch (error) {
						alert(error.message);
					}
				};

				// Copy HTML button
				const copyHtmlBtn = document.createElement("button");
				copyHtmlBtn.textContent = "📄";
				copyHtmlBtn.title = getUIText("copyHTML");
				copyHtmlBtn.className = "uncloseai-btn-small";
				copyHtmlBtn.onclick = async () => {
					try {
						const htmlContent = marked.parse(response);
						await navigator.clipboard.writeText(htmlContent);
						const originalText = copyHtmlBtn.textContent;
						copyHtmlBtn.textContent = "✓";
						setTimeout(() => {
							copyHtmlBtn.textContent = originalText;
						}, 1000);
					} catch (error) {
						alert(error.message);
					}
				};

				messageActions.appendChild(ttsBtn);

				// Add download button initially (hidden until audio is generated)
				const aiDownloadBtn = document.createElement("button");
				aiDownloadBtn.textContent = "💾";
				aiDownloadBtn.title = getUIText("downloadChatAudio");
				aiDownloadBtn.className = "uncloseai-btn-small uncloseai-download-btn";
				aiDownloadBtn.style.display = "none"; // Hidden initially
				messageActions.appendChild(aiDownloadBtn);

				messageActions.appendChild(copyRawBtn);
				messageActions.appendChild(copyHtmlBtn);
				messageActions.appendChild(deleteBtn);
				aiMsg.appendChild(messageActions);
			} catch (error) {
				aiMsg.innerHTML = `<span style="color: #dc3545;">Error: ${error.message}</span>`;
			}

			chatArea.scrollTop = chatArea.scrollHeight;
		};

		sendBtn.onclick = sendMessageHandler;
		input.onkeydown = (e) => {
			if (e.key === "Enter" && !e.shiftKey) {
				e.preventDefault();
				sendMessageHandler();
			}
		};

		inputArea.appendChild(input);
		inputArea.appendChild(sendBtn);
		container.appendChild(inputArea);
		modal.appendChild(container);

		document.body.appendChild(modal);
		modal.showModal();

		modal.addEventListener("click", (e) => {
			if (e.target === modal) {
				modal.close();
				document.body.removeChild(modal);
				uncloseaiEmbeddedModalOpen = false;
			}
		});

		// Theme change monitoring
		const updateModalTheme = () => {
			const newTheme = detectCurrentTheme();
			const newColors = getThemeColors(newTheme);
			modal.setAttribute("data-theme", newTheme);

			// Update CSS custom properties for theme support
			const root = document.documentElement;
			root.style.setProperty(
				"--uncloseai-button-background",
				newColors.buttonBackground,
			);
			root.style.setProperty("--uncloseai-button-hover", newColors.buttonHover);
			root.style.setProperty(
				"--uncloseai-button-border",
				newColors.buttonBorder,
			);
			root.style.setProperty("--uncloseai-primary-text", newColors.primaryText);
			root.style.setProperty(
				"--uncloseai-action-background",
				newColors.actionBackground,
			);
			root.style.setProperty("--uncloseai-action-hover", newColors.actionHover);
			root.style.setProperty(
				"--uncloseai-action-border",
				newColors.actionBorder,
			);
			root.style.setProperty("--uncloseai-action-text", newColors.primaryText);

			// Update CSS variables for dynamic theming
			root.style.setProperty(
				"--uncloseai-modal-background",
				newColors.modalBackground,
			);
			root.style.setProperty(
				"--uncloseai-content-background",
				newColors.contentBackground,
			);
			root.style.setProperty(
				"--uncloseai-panel-background",
				newColors.panelBackground,
			);
			root.style.setProperty(
				"--uncloseai-input-background",
				newColors.inputBackground,
			);
			root.style.setProperty(
				"--uncloseai-divider-color",
				newColors.dividerColor,
			);
			root.style.setProperty("--uncloseai-border-color", newColors.borderColor);

			// Update modal theme attribute
			modal.setAttribute("data-theme", detectCurrentTheme());

			// Control buttons now use CSS classes and variables

			// Message bubbles now use CSS classes with theme support
		};

		// Set up theme change listeners
		const themeObserver = new MutationObserver(updateModalTheme);
		themeObserver.observe(document.documentElement, {
			attributes: true,
			attributeFilter: ["data-theme"],
		});

		if (window.matchMedia) {
			window
				.matchMedia("(prefers-color-scheme: dark)")
				.addEventListener("change", updateModalTheme);
		}

		// Clean up listeners when modal is closed
		const originalClose = modal.close.bind(modal);
		modal.close = () => {
			themeObserver.disconnect();
			if (window.matchMedia) {
				window
					.matchMedia("(prefers-color-scheme: dark)")
					.removeEventListener("change", updateModalTheme);
			}
			originalClose();
		};

		// --- VAULT GATE: mandatory password before any chat ---
		const vaultGate = document.createElement("div");
		vaultGate.id = "uncloseai-vault-gate";
		vaultGate.className = "uncloseai-vault-gate";

		function showVaultGate() {
			const hasVault = UncloseVault.hasVault();
			vaultGate.innerHTML = "";
			vaultGate.style.display = "flex";

			const gateCard = document.createElement("div");
			gateCard.className = "uncloseai-vault-card";

			const icon = document.createElement("div");
			icon.className = "uncloseai-vault-icon";
			icon.textContent = hasVault ? "\u{1F513}" : "\u{1F510}";
			gateCard.appendChild(icon);

			const title = document.createElement("div");
			title.className = "uncloseai-vault-title";
			title.textContent = getUIText("vaultGateTitle");
			gateCard.appendChild(title);

			const explanation = document.createElement("div");
			explanation.className = "uncloseai-vault-explanation";
			explanation.textContent = hasVault ? getUIText("vaultGateReturning") : getUIText("vaultGateNew");
			gateCard.appendChild(explanation);

			const passwordInput = document.createElement("input");
			passwordInput.type = "password";
			passwordInput.className = "uncloseai-vault-input";
			passwordInput.placeholder = getUIText("vaultPasswordPlaceholder");
			gateCard.appendChild(passwordInput);

			const submitBtn = document.createElement("button");
			submitBtn.className = "uncloseai-vault-submit";
			submitBtn.textContent = hasVault ? getUIText("vaultGateUnlock") : getUIText("vaultGateCreate");
			gateCard.appendChild(submitBtn);

			const errorDiv = document.createElement("div");
			errorDiv.className = "uncloseai-vault-error";
			gateCard.appendChild(errorDiv);

			submitBtn.onclick = () => {
				const password = passwordInput.value;
				// Check fresh vault state (not stale closure)
				const vaultExists = UncloseVault.hasVault();
				if (vaultExists) {
					const result = UncloseVault.unlock(password);
					if (result.success) {
						vaultGate.style.display = "none";
						buildVaultUI();
						refreshSettingsFromVault();
						startChat();
					} else {
						errorDiv.textContent = getUIText("vaultWrongPassword");
						errorDiv.style.display = "block";
						passwordInput.value = "";
						passwordInput.focus();
					}
				} else {
					if (password.length < 8) {
						errorDiv.textContent = getUIText("vaultPasswordTooShort");
						errorDiv.style.display = "block";
						return;
					}
					const result = UncloseVault.create(password);
					if (result.success) {
						migrateSettingsToVault();
						vaultGate.style.display = "none";
						buildVaultUI();
						refreshSettingsFromVault();
						startChat();
					} else {
						errorDiv.textContent = result.error;
						errorDiv.style.display = "block";
					}
				}
			};

			passwordInput.onkeydown = (e) => {
				if (e.key === "Enter") submitBtn.click();
			};

			vaultGate.appendChild(gateCard);
			container.appendChild(vaultGate);

			// Auto-focus the password input
			setTimeout(() => passwordInput.focus(), 100);
		}

		// Start chat: load models, load history, generate greeting
		function startChat() {
			// Restore UI elements hidden by lock
			settingsContent.style.display = "grid";
			inputArea.style.display = "";
			loadModels();
			loadHistory();
		}

		// Load conversation history
		const loadHistory = async () => {
			try {
				const history = await loadConversationHistory();
				console.log("Raw history from localStorage:", history);
				console.log("History length:", history ? history.length : 0);
				if (history && history.length > 0) {
					// Set up page context for existing conversation
					const pageContent = await extractWebpageContent();
					const pageTitle = document.title || window.location.hostname;

					// Computed intelligence: instant, no API call, free for returning users
					let computedContext = "";
					try {
						const computedIntel = computePageIntelligence(pageContent);
						computedContext = formatPageIntelligence(computedIntel);
					} catch (e) {
						console.warn("Computed page intelligence failed:", e);
					}

					const conversationContextAppend = `
${computedContext}
PAGE CONTEXT FOR THIS CONVERSATION:
You are embedded on the webpage: "${pageTitle}"
URI: ${window.location.href}

FULL PAGE CONTENT:
${pageContent}

You have complete knowledge of this page content and can reference any details, names, topics, or information mentioned on this page. Answer questions about the page content accurately and helpfully.`;

					setSystemMessageAppend(conversationContextAppend);

					// Sync the loaded history with the chat.js module
					const { updateChatHistory } = await import("./chat.js");
					const { getSystemMessage } = await import("./config.js");

					// Create new history with updated system message and loaded conversation
					// Echo is NOT added here - it's only added at LLM request time in chat.js
					const systemContent = await getSystemMessage();
					const newHistory = [
						{ role: "system", content: systemContent },
						...history,
					];

					// Update the chat.js module's history
					await updateChatHistory(newHistory);
					console.log(
						"Chat history synced with loaded data:",
						newHistory.length,
						"messages",
					);
					console.log("History to display:", history);
					// Display previous conversation
					history.forEach((msg, index) => {
						console.log(
							`Displaying message ${index}:`,
							msg.role,
							msg.content.substring(0, 50),
						);
						if (msg.role === "user") {
							const userMsg = document.createElement("div");
							userMsg.className = "user-message";

							// Add message text and actions inside the bubble
							const messageText = document.createElement("div");
							messageText.textContent = msg.content;
							messageText.className = "message-text";

							const userMessageActions = document.createElement("div");
							userMessageActions.className = "uncloseai-message-actions";

							const userTtsBtn = document.createElement("button");
							userTtsBtn.textContent = "🔊";
							userTtsBtn.title = getUIText("playText");
							userTtsBtn.className = "uncloseai-btn-small";

							// Store audio for pause/resume functionality
							let historicalUserAudio = null;

							userTtsBtn.onclick = async () => {
								const modalVoiceSelect = document.getElementById(
									"hermes-voice-select",
								);
								const selectedVoice = modalVoiceSelect?.value || "tts-1:alloy";

								// If audio is already playing, pause it
								if (historicalUserAudio && !historicalUserAudio.paused) {
									historicalUserAudio.pause();
									userTtsBtn.textContent = "🔊";
									return;
								}

								// If audio exists and is paused, resume it
								if (
									historicalUserAudio?.paused &&
									historicalUserAudio.currentTime > 0
								) {
									historicalUserAudio.play();
									userTtsBtn.textContent = "⏸️";
									return;
								}

								// Generate new audio
								const originalText = userTtsBtn.textContent;
								const originalTitle = userTtsBtn.title;
								userTtsBtn.textContent = "⏳";
								userTtsBtn.title = getUIText("processingContent");
								userTtsBtn.disabled = true;

								try {
									const result = await speakChatText(
										msg.content,
										selectedVoice,
										1.0,
									);
									historicalUserAudio = result.audio;

									// Show and set up the download button
									const downloadBtn = userMessageActions.querySelector(
										".uncloseai-download-btn",
									);
									if (downloadBtn) {
										downloadBtn.style.display = ""; // Show the button
										downloadBtn.onclick = async () => {
											try {
												const { generateTitleForTTS } = await import(
													"./tts.js"
												);
												const filename = await generateTitleForTTS(msg.content);
												const a = document.createElement("a");
												a.href = result.blobUrl;
												a.download = `${filename}.mp3`;
												a.click();
											} catch (error) {
												console.error("Error generating filename:", error);
												const a = document.createElement("a");
												a.href = result.blobUrl;
												a.download = "user-historical-message.mp3";
												a.click();
											}
										};
									}

									// Set up audio event handlers
									historicalUserAudio.onplay = () => {
										userTtsBtn.textContent = "⏸️";
										userTtsBtn.title = getUIText("pausedClickToResume");
									};

									historicalUserAudio.onpause = () => {
										userTtsBtn.textContent = "🔊";
										userTtsBtn.title = getUIText("playText");
									};

									historicalUserAudio.onended = () => {
										userTtsBtn.textContent = "🔊";
										userTtsBtn.title = getUIText("playText");
										historicalUserAudio = null;
									};

									// Auto-play the generated audio
									try {
										await historicalUserAudio.play();
									} catch (_playError) {
										userTtsBtn.textContent = "🔊";
									}
								} catch (error) {
									alert(error.message);
									userTtsBtn.textContent = originalText;
									userTtsBtn.title = originalTitle;
								} finally {
									userTtsBtn.disabled = false;
								}
							};

							const userDeleteBtn = document.createElement("button");
							userDeleteBtn.textContent = "🗑️";
							userDeleteBtn.title = getUIText("deleteMessage");
							userDeleteBtn.className = "uncloseai-btn-small";
							userDeleteBtn.onclick = async () => {
								// Remove from chat history by index
								const currentHistory = await loadConversationHistory();
								if (index >= 0 && index < currentHistory.length) {
									currentHistory.splice(index, 1);
									await saveConversationHistory(currentHistory);

									// Update the chat.js module history to match localStorage
									// Echo is NOT added here - it's only added at LLM request time in chat.js
									const { updateChatHistory } = await import("./chat.js");
									const { getSystemMessage } = await import("./config.js");
									const systemContent = await getSystemMessage();
									const newHistory = [
										{ role: "system", content: systemContent },
										...currentHistory,
									];
									await updateChatHistory(newHistory);
								}

								userMsg.remove();
							};

							userMessageActions.appendChild(userTtsBtn);

							// Add download button initially (hidden until audio is generated)
							const userHistoricalDownloadBtn =
								document.createElement("button");
							userHistoricalDownloadBtn.textContent = "💾";
							userHistoricalDownloadBtn.title = getUIText("downloadChatAudio");
							userHistoricalDownloadBtn.className =
								"uncloseai-btn-small uncloseai-download-btn";
							userHistoricalDownloadBtn.style.display = "none"; // Hidden initially
							userMessageActions.appendChild(userHistoricalDownloadBtn);

							userMessageActions.appendChild(userDeleteBtn);
							userMsg.appendChild(messageText);
							userMsg.appendChild(userMessageActions);
							chatBox.appendChild(userMsg);
							console.log("Added user message to chatBox");
						} else if (msg.role === "assistant") {
							const aiMsg = document.createElement("div");
							aiMsg.className = "ai-message";
							aiMsg.innerHTML = marked.parse(msg.content);

							// Add syntax highlighting to all code blocks
							aiMsg.querySelectorAll("pre code").forEach((block) => {
								hljs.highlightElement(block);
							});

							addCodeBlockCopyButtons(aiMsg);

							// Add TTS and delete buttons to historical AI messages
							const messageActions = document.createElement("div");
							messageActions.className = "uncloseai-message-actions";

							const ttsBtn = document.createElement("button");
							ttsBtn.textContent = "🔊";
							ttsBtn.title = getUIText("playText");
							ttsBtn.className = "uncloseai-btn-small";
							// Store audio for pause/resume functionality
							let historicalAudio = null;

							ttsBtn.onclick = async () => {
								const modalVoiceSelect = document.getElementById(
									"hermes-voice-select",
								);
								const selectedVoice = modalVoiceSelect?.value || "tts-1:alloy";

								// If audio is already playing, pause it
								if (historicalAudio && !historicalAudio.paused) {
									historicalAudio.pause();
									ttsBtn.textContent = "🔊";
									console.log("🔊 HISTORICAL TTS: Paused");
									return;
								}

								// If audio exists and is paused, resume it
								if (
									historicalAudio?.paused &&
									historicalAudio.currentTime > 0
								) {
									historicalAudio.play();
									ttsBtn.textContent = "⏸️";
									console.log("🔊 HISTORICAL TTS: Resumed");
									return;
								}

								// Generate new audio
								console.log("🔊 HISTORICAL TTS: Generating new audio");
								const originalText = ttsBtn.textContent;
								const _originalTitle = ttsBtn.title;
								ttsBtn.textContent = "⏳";
								ttsBtn.title = getUIText("processingContent");
								ttsBtn.disabled = true;

								try {
									const result = await speakChatText(
										msg.content,
										selectedVoice,
										1.0,
									);
									historicalAudio = result.audio;

									// Show and set up the download button
									const downloadBtn = messageActions.querySelector(
										".uncloseai-download-btn",
									);
									if (downloadBtn) {
										downloadBtn.style.display = ""; // Show the button
										downloadBtn.onclick = async () => {
											try {
												const { generateTitleForTTS } = await import(
													"./tts.js"
												);
												const filename = await generateTitleForTTS(msg.content);
												const a = document.createElement("a");
												a.href = result.blobUrl;
												a.download = `${filename}.mp3`;
												a.click();
											} catch (error) {
												console.error("Error generating filename:", error);
												const a = document.createElement("a");
												a.href = result.blobUrl;
												a.download = "historical-message.mp3";
												a.click();
											}
										};
									}

									// Set up audio event handlers
									historicalAudio.onplay = () => {
										ttsBtn.textContent = "⏸️";
										ttsBtn.title = getUIText("pausedClickToResume");
									};

									historicalAudio.onpause = () => {
										ttsBtn.textContent = "🔊";
										ttsBtn.title = getUIText("playText");
									};

									historicalAudio.onended = () => {
										ttsBtn.textContent = "🔊";
										ttsBtn.title = getUIText("playText");
										historicalAudio = null;
									};

									// Auto-play the generated audio
									try {
										await historicalAudio.play();
										console.log("🔊 HISTORICAL TTS: Playing new audio");
									} catch (playError) {
										console.log(
											"🔊 HISTORICAL TTS: Auto-play blocked:",
											playError.message,
										);
										ttsBtn.textContent = "🔊";
									}
								} catch (error) {
									console.error("🔊 HISTORICAL TTS: Failed with error:", error);
									alert(error.message);
									ttsBtn.textContent = originalText;
								} finally {
									ttsBtn.disabled = false;
								}
							};

							const deleteBtn = document.createElement("button");
							deleteBtn.textContent = "🗑️";
							deleteBtn.title = getUIText("deleteMessage");
							deleteBtn.className = "uncloseai-btn-small";
							deleteBtn.onclick = async () => {
								// Remove from chat history and localStorage by index
								const { loadConversationHistory, saveConversationHistory } =
									await import("./storage.js");
								const { updateChatHistory } = await import("./chat.js");

								const currentHistory = await loadConversationHistory();
								if (index >= 0 && index < currentHistory.length) {
									currentHistory.splice(index, 1);

									// Update both localStorage and chat.js module
									await saveConversationHistory(currentHistory);
									await updateChatHistory(currentHistory);
								}

								aiMsg.remove();
							};

							// Copy Raw (Markdown) button
							const copyRawBtn = document.createElement("button");
							copyRawBtn.textContent = "📋";
							copyRawBtn.title = getUIText("copyRawMarkdown");
							copyRawBtn.className = "uncloseai-btn-small";
							copyRawBtn.onclick = async () => {
								try {
									await navigator.clipboard.writeText(msg.content);
									const originalText = copyRawBtn.textContent;
									copyRawBtn.textContent = "✓";
									setTimeout(() => {
										copyRawBtn.textContent = originalText;
									}, 1000);
								} catch (error) {
									alert(error.message);
								}
							};

							// Copy HTML button
							const copyHtmlBtn = document.createElement("button");
							copyHtmlBtn.textContent = "📄";
							copyHtmlBtn.title = getUIText("copyHTML");
							copyHtmlBtn.className = "uncloseai-btn-small";
							copyHtmlBtn.onclick = async () => {
								try {
									const htmlContent = marked.parse(msg.content);
									await navigator.clipboard.writeText(htmlContent);
									const originalText = copyHtmlBtn.textContent;
									copyHtmlBtn.textContent = "✓";
									setTimeout(() => {
										copyHtmlBtn.textContent = originalText;
									}, 1000);
								} catch (error) {
									alert(error.message);
								}
							};

							messageActions.appendChild(ttsBtn);

							// Add download button initially (hidden until audio is generated)
							const aiHistoricalDownloadBtn = document.createElement("button");
							aiHistoricalDownloadBtn.textContent = "💾";
							aiHistoricalDownloadBtn.title = getUIText("downloadChatAudio");
							aiHistoricalDownloadBtn.className =
								"uncloseai-btn-small uncloseai-download-btn";
							aiHistoricalDownloadBtn.style.display = "none"; // Hidden initially
							messageActions.appendChild(aiHistoricalDownloadBtn);

							messageActions.appendChild(copyRawBtn);
							messageActions.appendChild(copyHtmlBtn);
							messageActions.appendChild(deleteBtn);
							aiMsg.appendChild(messageActions);

							chatBox.appendChild(aiMsg);
							console.log("Added AI message to chatBox with TTS buttons");
						}
					});
					chatArea.scrollTop = chatArea.scrollHeight;
				} else {
					// Add intro message if no history
					await addIntroMessage();
				}
			} catch (error) {
				console.error("Failed to load conversation history:", error);
				await addIntroMessage();
			}
		};

		const addIntroMessage = async () => {
			const introMsg = document.createElement("div");
			introMsg.className = "ai-message";

			// Show loading message first
			introMsg.innerHTML =
				'<em style="color: #6c757d;">Analyzing page and generating welcome message...</em>';
			chatBox.appendChild(introMsg);

			try {
				// Get page content for context
				const pageContent = await extractWebpageContent();
				const pageTitle = document.title || window.location.hostname;

				// COMPUTED INTELLIGENCE: instant, deterministic, zero API calls
				// Extracts ground truth measurements from DOM and content
				let computedContext = "";
				try {
					const computedIntel = computePageIntelligence(pageContent);
					computedContext = formatPageIntelligence(computedIntel);
					console.log("Computed page intelligence:", computedIntel);
				} catch (e) {
					console.warn("Computed page intelligence failed:", e);
				}

				// LLM CLASSIFICATION: async pre-inference for subjective analysis
				introMsg.innerHTML =
					'<em style="color: #6c757d;">Reading page...</em>';
				let analysisContext = "";
				try {
					const analysisPrompt = buildPageAnalysisPrompt(
						pageContent,
						pageTitle,
						window.location.href,
					);
					const analysisHistory = [
						{ role: "system", content: analysisPrompt.system },
						{ role: "user", content: analysisPrompt.user },
					];
					let analysisResponse = "";
					for await (const chunk of sendMessageWithCustomHistory(
						analysisHistory,
					)) {
						analysisResponse += chunk;
					}
					const pageAnalysis = parsePageAnalysis(analysisResponse);
					analysisContext = buildAnalysisContext(pageAnalysis);
					if (pageAnalysis) {
						console.log("Page analysis:", pageAnalysis);
					}
				} catch (e) {
					console.warn("Page pre-analysis failed, proceeding without:", e);
				}

				introMsg.innerHTML =
					'<em style="color: #6c757d;">Generating welcome message...</em>';

				// Generate intro message with specialized intro system prompt
				// Get user's preferred language and localize the system prompt
				const userLang = getUserLanguagePreference();
				const languageName = NATIVE_LANGUAGE_NAMES[userLang] || "English";

				// Build explicit language instruction for non-English languages
				const langInstruction =
					userLang !== "en"
						? `\n\nCRITICAL: You MUST write your ENTIRE response in ${languageName}. Do NOT write in English. Every word of your introduction must be in ${languageName}.`
						: "";

				// Greeting instructions vary by page type
				const hasIntelligence = computedContext || analysisContext;
				const typeGuidance = hasIntelligence
					? `\nUse the PAGE INTELLIGENCE and COMPUTED PAGE METRICS to shape your greeting style. Reference specific numbers (word count, reading time, code languages) naturally. For lyrics, discuss the music and emotions. For recipes, mention ingredients and techniques. For news, note how recent or dated the content is. For code or CI logs, reference the technology and build status. For manifestos or philosophy, engage with the ideas. For wikis, acknowledge the knowledge domain. For emails, understand the communication context. Match your tone to what the page actually is. Never mention "page intelligence", "computed metrics", or "pre-analysis" to the user.\n`
					: "";

				const introSystemPrompt = `${getUIText("systemPromptIntro")}
${computedContext}${analysisContext}${typeGuidance}
PAGE INFORMATION:
Title: "${pageTitle}"
URI: ${window.location.href}

FULL PAGE CONTENT:
${pageContent}

Generate a 3-paragraph introduction that:
${getUIText("systemPromptTask1")}
${getUIText("systemPromptTask2")}
${getUIText("systemPromptTask3")}

${getUIText("systemPromptInstructions")} ${languageName}.${langInstruction}`;

				const introPrompt =
					userLang !== "en"
						? `Generate the welcoming introduction message now. Remember: Write ONLY in ${languageName}, not English.`
						: "Generate the welcoming introduction message now.";

				// Create temporary chat history for intro generation
				const introHistory = [
					{ role: "system", content: introSystemPrompt },
					{ role: "user", content: introPrompt },
				];

				// Generate intro with specialized system prompt
				let response = "";
				for await (const chunk of sendMessageWithCustomHistory(introHistory)) {
					response += chunk;
					introMsg.innerHTML = marked.parse(response);
				}

				// Streaming is complete - now add final processing
				introMsg.innerHTML = marked.parse(response);

				// Add syntax highlighting to all code blocks
				introMsg.querySelectorAll("pre code").forEach((block) => {
					hljs.highlightElement(block);
				});

				// Add copy buttons after highlighting
				addCodeBlockCopyButtons(introMsg);

				// SECOND: Set up conversation system prompt for follow-up messages
				// Include the analysis so follow-up messages inherit the classified context
				const conversationContextAppend = `
${computedContext}${analysisContext}
PAGE CONTEXT FOR THIS CONVERSATION:
You are embedded on the webpage: "${pageTitle}"
URI: ${window.location.href}

FULL PAGE CONTENT:
${pageContent}

You have complete knowledge of this page content and can reference any details, names, topics, or information mentioned on this page. Answer questions about the page content accurately and helpfully.`;

				setSystemMessageAppend(conversationContextAppend);

				// Update the chat.js module with the intro message
				const { updateChatHistory, getChatHistory } = await import("./chat.js");
				const { getSystemMessage } = await import("./config.js");

				// Create new history with system message and intro
				// Echo is NOT added here - it's only added at LLM request time in chat.js
				const systemContent = await getSystemMessage();
				const newHistory = [
					{ role: "system", content: systemContent },
					{ role: "assistant", content: response },
				];

				// Update the chat.js module's history
				await updateChatHistory(newHistory);
				console.log("Added intro message to chat history");

				// Add TTS and delete buttons to intro message
				const messageActions = document.createElement("div");
				messageActions.className = "uncloseai-message-actions";

				const ttsBtn = document.createElement("button");
				ttsBtn.textContent = "🔊";
				ttsBtn.title = "Read aloud";
				ttsBtn.className = "uncloseai-btn-small";

				// Store audio for pause/resume functionality
				let introAudio = null;

				ttsBtn.onclick = async () => {
					const modalVoiceSelect = document.getElementById(
						"hermes-voice-select",
					);
					const selectedVoice = modalVoiceSelect?.value || "tts-1:alloy";

					// If audio is already playing, pause it
					if (introAudio && !introAudio.paused) {
						introAudio.pause();
						ttsBtn.textContent = "🔊";
						console.log("🔊 INTRO TTS: Paused");
						return;
					}

					// If audio exists and is paused, resume it
					if (introAudio?.paused && introAudio.currentTime > 0) {
						introAudio.play();
						ttsBtn.textContent = "⏸️";
						console.log("🔊 INTRO TTS: Resumed");
						return;
					}

					// Generate new audio
					console.log("🔊 INTRO TTS: Generating new audio");
					const originalText = ttsBtn.textContent;
					ttsBtn.textContent = "⏳";
					ttsBtn.disabled = true;

					try {
						const result = await speakChatText(response, selectedVoice, 1.0);
						introAudio = result.audio;

						// Set up audio event handlers
						introAudio.onplay = () => {
							ttsBtn.textContent = "⏸️";
						};

						introAudio.onpause = () => {
							ttsBtn.textContent = "🔊";
						};

						introAudio.onended = () => {
							ttsBtn.textContent = "🔊";
							introAudio = null;
						};

						// Auto-play the generated audio
						try {
							await introAudio.play();
							console.log("🔊 INTRO TTS: Playing new audio");
						} catch (playError) {
							console.log(
								"🔊 INTRO TTS: Auto-play blocked:",
								playError.message,
							);
							ttsBtn.textContent = "🔊";
						}
					} catch (error) {
						console.error("🔊 INTRO TTS: Failed with error:", error);
						alert(error.message);
						ttsBtn.textContent = originalText;
					} finally {
						ttsBtn.disabled = false;
					}
				};

				const deleteBtn = document.createElement("button");
				deleteBtn.textContent = "🗑️";
				deleteBtn.title = getUIText("deleteMessage");
				deleteBtn.className = "uncloseai-btn-small";
				deleteBtn.onclick = async () => {
					// Remove intro message from localStorage
					const { loadConversationHistory, saveConversationHistory } =
						await import("./storage.js");
					const { updateChatHistory } = await import("./chat.js");

					const currentHistory = await loadConversationHistory();
					const updatedHistory = currentHistory.filter(
						(msg) => !(msg.role === "assistant" && msg.content === response),
					);

					// Update both localStorage and chat.js module
					await saveConversationHistory(updatedHistory);
					await updateChatHistory(updatedHistory);

					introMsg.remove();
				};

				// Copy Raw (Markdown) button
				const copyRawBtn = document.createElement("button");
				copyRawBtn.textContent = "📋";
				copyRawBtn.title = getUIText("copyRawMarkdown");
				copyRawBtn.className = "uncloseai-btn-small";
				copyRawBtn.onclick = async () => {
					try {
						await navigator.clipboard.writeText(response);
						const originalText = copyRawBtn.textContent;
						copyRawBtn.textContent = "✓";
						setTimeout(() => {
							copyRawBtn.textContent = originalText;
						}, 1000);
					} catch (error) {
						alert(error.message);
					}
				};

				// Copy HTML button
				const copyHtmlBtn = document.createElement("button");
				copyHtmlBtn.textContent = "📄";
				copyHtmlBtn.title = getUIText("copyHTML");
				copyHtmlBtn.className = "uncloseai-btn-small";
				copyHtmlBtn.onclick = async () => {
					try {
						const htmlContent = marked.parse(response);
						await navigator.clipboard.writeText(htmlContent);
						const originalText = copyHtmlBtn.textContent;
						copyHtmlBtn.textContent = "✓";
						setTimeout(() => {
							copyHtmlBtn.textContent = originalText;
						}, 1000);
					} catch (error) {
						alert(error.message);
					}
				};

				messageActions.appendChild(ttsBtn);
				messageActions.appendChild(copyRawBtn);
				messageActions.appendChild(copyHtmlBtn);
				messageActions.appendChild(deleteBtn);
				introMsg.appendChild(messageActions);

				// Save this intro as part of the conversation
				await saveConversationHistory(await getChatHistory());
			} catch (error) {
				console.error("Failed to generate contextual intro:", error);
				// Fallback to basic intro
				introMsg.innerHTML = `👋 Hi! I'm Hermes AI. I can help you understand this page, answer questions, or assist with various tasks. How can I help you today?`;
			}
		};

		// --- VAULT GATE CHECK: show gate or proceed to chat ---
		if (UncloseVault.isAvailable() && UncloseVault.isUnlocked()) {
			// Vault already unlocked (session persisted) — go straight to chat
			loadModels();
			await loadHistory();
		} else if (UncloseVault.isAvailable()) {
			// Vault available but locked — show gate, chat starts on unlock
			showVaultGate();
		} else {
			// CryptoJS not loaded — fallback (shouldn't happen, ensureCryptoJS above)
			loadModels();
			await loadHistory();
		}
	} catch (error) {
		console.error("Failed to open modal:", error);
		// Fallback: ensure some basic modal is available
		const fallbackModal = document.createElement("dialog");
		fallbackModal.innerHTML =
			"<p>Error loading modal. Please refresh the page.</p>";
		document.body.appendChild(fallbackModal);
		fallbackModal.showModal();
	}
}

// Function to toggle Hermes modal
let uncloseaiEmbeddedModalOpen = false;

async function toggleUncloseaiEmbeddedModal() {
	if (uncloseaiEmbeddedModalOpen) {
		const existingModal = document.getElementById("uncloseai-embedded-modal");
		if (existingModal) {
			existingModal.close();
			document.body.removeChild(existingModal);
		}
		uncloseaiEmbeddedModalOpen = false;
	} else {
		await openUncloseaiEmbeddedModalNew();
		uncloseaiEmbeddedModalOpen = true;
	}
}

// Export the modal functions
export { toggleUncloseaiEmbeddedModal, openUncloseaiEmbeddedModalNew };

// Export compatibility alias
export const openUncloseaiEmbeddedModal = toggleUncloseaiEmbeddedModal;
