// PUBLIC DOMAIN - NO LICENSE, NO WARRANTY
//
// This is free public domain 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
//
// Anyone is free to copy, modify, publish, use, compile, sell, or distribute
// this software, either in source code form or as a compiled binary, for any
// purpose, commercial or non-commercial, and by any means.
//
// NO WARRANTY. THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
//
// Copyright 2025-2026 TimeHexOn & foxhop & russell@unturf
// https://www.permacomputer.com

/*
 * uncloseai.js - Modular AI Integration Library
 *
 * Main entry point that imports all modules and exports the public API
 * This maintains backward compatibility while enabling better code organization
 */

import * as Chat from "./src/chat.js";
// Internal modules
import * as Config from "./src/config.js";
import * as Content from "./src/content.js";
import * as FileUpload from "./src/file-upload.js";
import * as Models from "./src/models.js";
import * as PageReader from "./src/page-reader.js";
import * as Storage from "./src/storage.js";
import * as Translation from "./src/translation.js";
import * as TTS from "./src/tts.js";
import * as UI from "./src/ui.js";
import { UncloseVault } from "./src/vault.js";

// Duplicate load guard: if a page already includes uncloseai.js natively,
// the extension should not re-initialize. Module exports remain available,
// but window globals, event listeners, and DOM side effects only run once.
const __alreadyLoaded = window.__UNCLOSEAI_LOADED__ === true;
window.__UNCLOSEAI_LOADED__ = true;

// -------------------------
// Vault Support
// -------------------------

// Load CryptoJS dynamically for vault encryption
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('uncloseai.js: Failed to load CryptoJS - vault features disabled');
			resolve(false);
		};
		document.head.appendChild(script);
	});
}

// Export vault for external use
export { UncloseVault };

// -------------------------
// Public API - Main Functions
// -------------------------

// Chat functionality
export const sendMessage = Chat.sendMessage;
export const handleUserInput = Chat.handleUserInput;

// TTS functionality
export const speakText = TTS.speakText;
export const processContentWithHermes = TTS.processContentWithHermes;
export const extractSpokenTokens = TTS.extractSpokenTokens;
export const generateTitleForTTS = TTS.generateTitleForTTS;

// File upload
export const uploadFile = FileUpload.uploadFile;
export const integrateMegafarceResponse = FileUpload.integrateMegafarceResponse;
export const showProgressIndicator = FileUpload.showProgressIndicator;
export const hideProgressIndicator = FileUpload.hideProgressIndicator;

// Page reading
export const readPageWithHermes = PageReader.readPageWithHermes;
export const extractWebpageContent = Content.extractWebpageContent;

// Model management
export const getSelectedModel = Models.getSelectedModel;
export const getSelectedModelEndpoint = Models.getSelectedModelEndpoint;
export const fetchModelsFromEndpoints = Models.fetchModelsFromEndpoints;
export const createModelSelectionDropdown = Models.createModelSelectionDropdown;
export const addRefreshModelsButton = Models.addRefreshModelsButton;

// Storage
export const saveConversationHistory = Storage.saveConversationHistory;
export const loadConversationHistory = Storage.loadConversationHistory;
export const clearConversationHistory = Storage.clearConversationHistory;
export const getPageSpecificKey = Storage.getPageSpecificKey;

// UI creation
export const createFloatingAIButton = UI.createFloatingAIButton;
export const initializeUncloseaiElements = UI.initializeUncloseaiElements;
export const createFullInterface = UI.createFullInterface;
export const createCustomInterface = UI.createCustomInterface;
export const toggleUncloseaiEmbeddedModal = UI.toggleUncloseaiEmbeddedModal;
export const openUncloseaiEmbeddedModal = UI.openUncloseaiEmbeddedModal;
export const openTTSModal = UI.openTTSModal;
export const openTranslateModal = UI.openTranslateModal;

// Translation functionality
export const translateText = Translation.translateText;
export const translateCurrentPage = Translation.translateCurrentPage;
export const translateHTML = Translation.translateHTML;

// -------------------------
// Configuration and State
// -------------------------

// Export configuration constants
export const TTS_API_URL = Config.TTS_API_URL;
export const MEGAPARCE_API_URL = Config.MEGAPARCE_API_URL;
export const API_KEY = Config.API_KEY;
export const MODEL = Config.MODEL;
export const VLLM_ENDPOINTS = Config.VLLM_ENDPOINTS;

// Export model registry
export const modelRegistry = Models.modelRegistry;

// Export chat history (for external access)
export { chatHistory } from "./src/chat.js";

// -------------------------
// Initialization
// -------------------------

// -------------------------
// Global Scope Exports (for backward compatibility)
// Side effects only run once: if the page already loaded uncloseai.js,
// the extension copy skips initialization but module exports still work.
// -------------------------

if (!__alreadyLoaded) {
	// Export ALL functions under window.uncloseai namespace to avoid clobbering
	// host page globals (e.g. a page's own sendMessage, speakText, etc.)
	window.uncloseai = {
		handleUserInput: Chat.handleUserInput,
		readPageWithHermes: PageReader.readPageWithHermes,
		sendMessage: Chat.sendMessage,
		speakText: TTS.speakText,
		uploadFile: FileUpload.uploadFile,
		openTTSModal: UI.openTTSModal,
		openTranslateModal: UI.openTranslateModal,
		toggleUncloseaiEmbeddedModal: async () =>
			await UI.toggleUncloseaiEmbeddedModal(),
		extractWebpageContent: Content.extractWebpageContent,
		getSelectedModel: Models.getSelectedModel,
		getSelectedModelEndpoint: Models.getSelectedModelEndpoint,
		showProgressIndicator: FileUpload.showProgressIndicator,
		hideProgressIndicator: FileUpload.hideProgressIndicator,
		handleTTSFromElement: UI.handleTTSFromElement,
		handleUploadFromElement: UI.handleUploadFromElement,
		handleSmartTranslate: UI.handleSmartTranslate,
		UncloseVault: UncloseVault,
	};

	// Only set uniquely-named globals that internal extension modules depend on.
	// NEVER set generic names (sendMessage, speakText, handleUserInput, uploadFile,
	// getSelectedModel, etc.) directly on window — they clobber host page functions.
	window.UncloseVault = UncloseVault;
	window.toggleUncloseaiEmbeddedModal = async () =>
		await UI.toggleUncloseaiEmbeddedModal();
	window.openTTSModal = UI.openTTSModal;
	window.openTranslateModal = UI.openTranslateModal;
	window.handleTTSFromElement = UI.handleTTSFromElement;
	window.handleUploadFromElement = UI.handleUploadFromElement;
	window.handleSmartTranslate = UI.handleSmartTranslate;

	// Initialize on page load
	window.addEventListener("load", async () => {
		console.log("uncloseai.js: window.onload event fired.");

		// Load CryptoJS and initialize vault early
		await ensureCryptoJS();
		if (UncloseVault.isAvailable()) {
			const restored = UncloseVault.init();
			console.log(
				"uncloseai.js: Vault initialized, session restored:",
				restored,
			);
		}

		// Check skip init flag first
		if (window.UNCLOSEAI_SKIP_INIT === true) {
			console.log(
				"uncloseai.js: Skipping full initialization as requested by flag.",
			);
			console.log(
				"uncloseai.js: Creating floating button only for preview windows.",
			);

			// Still create floating button for preview windows, but skip other initialization
			const SHOW_FLOATING_BUTTON =
				window.UNCLOSEAI_FLOATING_BUTTON !== false;
			if (SHOW_FLOATING_BUTTON) {
				UI.createFloatingAIButton();
			}
			return;
		}

		UI.initializeSystem();
	});

	// Export helper functions for class-based integrations
	window.uncloseai.handleCustomChat = async (button) => {
		const container = button.parentElement;
		const input = container.querySelector("[data-chat-input]");
		const chatBox = container.querySelector("[data-chat-box]");
		const message = input.value.trim();

		if (!message) return;

		// Add user message
		chatBox.innerHTML += `<div style="margin: 2px 0; padding: 2px; background: #e3f2fd; border-radius: 2px; font-size: 0.9em;"><strong>You:</strong> ${message}</div>`;
		input.value = "";

		// Add AI thinking indicator
		const thinkingDiv = document.createElement("div");
		thinkingDiv.style.cssText =
			"margin: 2px 0; padding: 2px; background: #f5f5f5; border-radius: 2px; font-size: 0.9em;";
		thinkingDiv.innerHTML = "<strong>AI:</strong> <em>thinking...</em>";
		chatBox.appendChild(thinkingDiv);
		chatBox.scrollTop = chatBox.scrollHeight;

		try {
			let response = "";
			for await (const chunk of Chat.sendMessage(message)) {
				response += chunk;
				thinkingDiv.innerHTML = `<strong>AI:</strong> ${response}`;
				chatBox.scrollTop = chatBox.scrollHeight;
			}
		} catch (error) {
			thinkingDiv.innerHTML = `<strong>Error:</strong> ${error.message}`;
		}
	};

	console.log("uncloseai.js: Modular version loaded successfully");
} else {
	console.log(
		"uncloseai.js: page already has uncloseai loaded, skipping duplicate initialization",
	);
}
