import { writable } from "svelte/store";
import { invoke } from "@tauri-apps/api/core";
import { save, open } from "@tauri-apps/plugin-dialog";
import type { Conversation } from "./conversations";
import { writeTextFile, readTextFile } from "@tauri-apps/plugin-fs";
import { openPath } from "@tauri-apps/plugin-opener";

// Debounce delay for auto-save (in milliseconds)
const AUTO_SAVE_DEBOUNCE_MS = 2000;

export interface SavedMessage {
  id: string;
  type: string;
  content: string;
  timestamp: string;
  tool_name?: string;
}

export interface SavedSession {
  id: string;
  name: string;
  created_at: string;
  last_activity_at: string;
  working_directory: string;
  message_count: number;
  preview: string;
  messages: SavedMessage[];
}

export interface SessionListItem {
  id: string;
  name: string;
  created_at: string;
  last_activity_at: string;
  working_directory: string;
  message_count: number;
  preview: string;
}

function escapeHtml(text: string): string {
  return text
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
}

function generateHtmlExport(session: SavedSession, includeMetadata: boolean): string {
  const styles = `
    :root {
      --bg-primary: #1a1a2e;
      --bg-secondary: #16213e;
      --bg-code: #1e1e2e;
      --accent-primary: #e94560;
      --text-primary: #ffffff;
      --text-secondary: #a0a0a0;
      --border-color: #2a2a4a;
      --terminal-user: #22d3ee;
      --terminal-tool: #c084fc;
      --terminal-error: #f87171;
      --hljs-keyword: #f472b6;
      --hljs-string: #a3e635;
      --hljs-number: #fbbf24;
      --hljs-comment: #6b7280;
      --hljs-function: #c084fc;
      --hljs-type: #22d3ee;
    }
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body {
      font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
      background: var(--bg-primary);
      color: var(--text-primary);
      line-height: 1.6;
      padding: 2rem;
      max-width: 900px;
      margin: 0 auto;
    }
    h1 { color: var(--accent-primary); margin-bottom: 1rem; }
    .metadata {
      background: var(--bg-secondary);
      padding: 1rem;
      border-radius: 8px;
      margin-bottom: 2rem;
      border: 1px solid var(--border-color);
    }
    .metadata p { color: var(--text-secondary); margin: 0.25rem 0; }
    .metadata strong { color: var(--text-primary); }
    hr { border: none; border-top: 1px solid var(--border-color); margin: 1.5rem 0; }
    .message {
      background: var(--bg-secondary);
      border-radius: 8px;
      padding: 1rem;
      margin-bottom: 1rem;
      border-left: 4px solid var(--border-color);
    }
    .message.user { border-left-color: var(--terminal-user); }
    .message.assistant { border-left-color: var(--accent-primary); }
    .message.tool_use { border-left-color: var(--terminal-tool); }
    .message.tool_result { border-left-color: var(--hljs-string); }
    .message.error { border-left-color: var(--terminal-error); }
    .message.system { border-left-color: var(--text-secondary); }
    .message-header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 0.5rem;
      padding-bottom: 0.5rem;
      border-bottom: 1px solid var(--border-color);
    }
    .message-type {
      font-weight: bold;
      text-transform: capitalize;
    }
    .message-type.user { color: var(--terminal-user); }
    .message-type.assistant { color: var(--accent-primary); }
    .message-type.tool_use { color: var(--terminal-tool); }
    .message-type.tool_result { color: var(--hljs-string); }
    .message-type.error { color: var(--terminal-error); }
    .message-type.system { color: var(--text-secondary); }
    .timestamp { color: var(--text-secondary); font-size: 0.85rem; }
    .tool-name { color: var(--terminal-tool); font-size: 0.9rem; }
    .message-content {
      white-space: pre-wrap;
      word-wrap: break-word;
      font-family: 'Consolas', 'Monaco', monospace;
      font-size: 0.9rem;
    }
    pre {
      background: var(--bg-code);
      padding: 1rem;
      border-radius: 4px;
      overflow-x: auto;
      margin: 0.5rem 0;
    }
    code {
      font-family: 'Consolas', 'Monaco', monospace;
      font-size: 0.85rem;
    }
    .footer {
      text-align: center;
      color: var(--text-secondary);
      margin-top: 2rem;
      padding-top: 1rem;
      border-top: 1px solid var(--border-color);
    }
    @media (prefers-color-scheme: light) {
      :root {
        --bg-primary: #f8f9fa;
        --bg-secondary: #ffffff;
        --bg-code: #f5f5f5;
        --text-primary: #1a1a2e;
        --text-secondary: #5a5a7a;
        --border-color: #d0d0e0;
        --terminal-user: #0891b2;
        --terminal-tool: #7c3aed;
        --terminal-error: #dc2626;
        --hljs-keyword: #d946ef;
        --hljs-string: #16a34a;
      }
    }
  `;

  let messagesHtml = "";
  for (const message of session.messages) {
    const timestamp = new Date(message.timestamp).toLocaleString();
    const typeLabel =
      message.type === "tool_use"
        ? "Tool Use"
        : message.type === "tool_result"
          ? "Tool Result"
          : message.type.charAt(0).toUpperCase() + message.type.slice(1);

    messagesHtml += `
      <div class="message ${message.type}">
        <div class="message-header">
          <span class="message-type ${message.type}">${typeLabel}</span>
          <span class="timestamp">${timestamp}</span>
        </div>
        ${message.tool_name ? `<div class="tool-name">🔧 ${escapeHtml(message.tool_name)}</div>` : ""}
        <div class="message-content">${escapeHtml(message.content)}</div>
      </div>
    `;
  }

  const metadataHtml = includeMetadata
    ? `
    <div class="metadata">
      <p><strong>Created:</strong> ${new Date(session.created_at).toLocaleString()}</p>
      <p><strong>Last Activity:</strong> ${new Date(session.last_activity_at).toLocaleString()}</p>
      <p><strong>Working Directory:</strong> ${session.working_directory || "Not set"}</p>
      <p><strong>Messages:</strong> ${session.message_count}</p>
    </div>
  `
    : "";

  return `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>${escapeHtml(session.name)} - Hikari Desktop Export</title>
  <style>${styles}</style>
</head>
<body>
  <h1>💬 ${escapeHtml(session.name)}</h1>
  ${metadataHtml}
  <hr>
  ${messagesHtml}
  <div class="footer">
    <p>✨ Exported from Hikari Desktop</p>
    <p>Export date: ${new Date().toLocaleString()}</p>
  </div>
</body>
</html>`;
}

function generatePrintableHtml(session: SavedSession, includeMetadata: boolean): string {
  const printStyles = `
    * { box-sizing: border-box; margin: 0; padding: 0; }
    body {
      font-family: 'Georgia', 'Times New Roman', serif;
      font-size: 11pt;
      line-height: 1.5;
      padding: 0.5in;
      max-width: 8.5in;
      margin: 0 auto;
      color: #000;
      background: #fff;
    }
    h1 {
      font-size: 18pt;
      margin-bottom: 0.25in;
      border-bottom: 2px solid #333;
      padding-bottom: 0.1in;
    }
    .metadata {
      background: #f5f5f5;
      padding: 0.15in;
      margin-bottom: 0.25in;
      border: 1px solid #ddd;
      font-size: 9pt;
    }
    .metadata p { margin: 2pt 0; }
    hr { border: none; border-top: 1px solid #ccc; margin: 0.2in 0; }
    .message {
      margin-bottom: 0.15in;
      padding: 0.1in;
      border-left: 3px solid #ccc;
      page-break-inside: avoid;
    }
    .message.user { border-left-color: #0088cc; }
    .message.assistant { border-left-color: #cc0044; }
    .message.tool_use { border-left-color: #8844cc; }
    .message.tool_result { border-left-color: #44cc44; }
    .message.error { border-left-color: #cc4444; }
    .message.system { border-left-color: #888; }
    .message-header {
      display: flex;
      justify-content: space-between;
      font-size: 9pt;
      color: #666;
      margin-bottom: 0.05in;
      border-bottom: 1px dotted #ddd;
      padding-bottom: 0.03in;
    }
    .message-type { font-weight: bold; text-transform: uppercase; }
    .message-type.user { color: #0066aa; }
    .message-type.assistant { color: #aa0033; }
    .message-type.tool_use { color: #6633aa; }
    .message-type.tool_result { color: #33aa33; }
    .message-type.error { color: #aa3333; }
    .tool-name { color: #666; font-size: 9pt; font-style: italic; }
    .message-content {
      white-space: pre-wrap;
      word-wrap: break-word;
      font-family: 'Consolas', 'Courier New', monospace;
      font-size: 9pt;
      background: #fafafa;
      padding: 0.05in;
    }
    .footer {
      text-align: center;
      font-size: 8pt;
      color: #999;
      margin-top: 0.25in;
      padding-top: 0.1in;
      border-top: 1px solid #ddd;
    }
    .print-instructions {
      background: #ffffcc;
      border: 1px solid #cccc00;
      padding: 0.15in;
      margin-bottom: 0.25in;
      font-size: 10pt;
    }
    .print-instructions h2 { font-size: 12pt; margin-bottom: 0.1in; }
    .print-instructions ol { margin-left: 0.2in; }
    .print-instructions li { margin: 0.05in 0; }
    @media print {
      .print-instructions { display: none; }
      body { padding: 0; }
    }
    @page { margin: 0.5in; }
  `;

  let messagesHtml = "";
  for (const message of session.messages) {
    const timestamp = new Date(message.timestamp).toLocaleString();
    const typeLabel =
      message.type === "tool_use"
        ? "Tool"
        : message.type === "tool_result"
          ? "Result"
          : message.type.charAt(0).toUpperCase() + message.type.slice(1);

    messagesHtml += `
      <div class="message ${message.type}">
        <div class="message-header">
          <span class="message-type ${message.type}">${typeLabel}</span>
          <span class="timestamp">${timestamp}</span>
        </div>
        ${message.tool_name ? `<div class="tool-name">${escapeHtml(message.tool_name)}</div>` : ""}
        <div class="message-content">${escapeHtml(message.content)}</div>
      </div>
    `;
  }

  const metadataHtml = includeMetadata
    ? `
    <div class="metadata">
      <p><strong>Created:</strong> ${new Date(session.created_at).toLocaleString()}</p>
      <p><strong>Last Activity:</strong> ${new Date(session.last_activity_at).toLocaleString()}</p>
      <p><strong>Working Directory:</strong> ${session.working_directory || "Not set"}</p>
      <p><strong>Messages:</strong> ${session.message_count}</p>
    </div>
  `
    : "";

  return `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>${escapeHtml(session.name)} - Print to PDF</title>
  <style>${printStyles}</style>
</head>
<body>
  <div class="print-instructions">
    <h2>Print to PDF Instructions</h2>
    <ol>
      <li>Press <strong>Ctrl+P</strong> (or <strong>Cmd+P</strong> on Mac) to open the print dialog</li>
      <li>Select <strong>"Save as PDF"</strong> or <strong>"Microsoft Print to PDF"</strong> as the printer</li>
      <li>Click <strong>Print</strong> to save your PDF</li>
    </ol>
    <p><em>This instruction box will not appear in your PDF.</em></p>
  </div>
  <h1>${escapeHtml(session.name)}</h1>
  ${metadataHtml}
  <hr>
  ${messagesHtml}
  <div class="footer">
    <p>Exported from Hikari Desktop | ${new Date().toLocaleString()}</p>
  </div>
</body>
</html>`;
}

function createSessionsStore() {
  const sessions = writable<SessionListItem[]>([]);
  const isLoading = writable(false);
  const searchQuery = writable("");

  // Track pending auto-save timeouts per conversation
  const pendingAutoSaves = new Map<string, ReturnType<typeof setTimeout>>();

  async function loadSessions(): Promise<void> {
    isLoading.set(true);
    try {
      const result = await invoke<SessionListItem[]>("list_sessions");
      sessions.set(result);
    } catch (error) {
      console.error("Failed to load sessions:", error);
    } finally {
      isLoading.set(false);
    }
  }

  async function saveConversation(conversation: Conversation): Promise<void> {
    const messages: SavedMessage[] = conversation.terminalLines.map((line) => ({
      id: line.id,
      type: line.type,
      content: line.content,
      timestamp: line.timestamp.toISOString(),
      tool_name: line.toolName,
    }));

    const userAndAssistantMessages = conversation.terminalLines.filter(
      (line) => line.type === "user" || line.type === "assistant"
    );
    const previewContent =
      userAndAssistantMessages
        .slice(0, 3)
        .map((m) => m.content)
        .join(" ")
        .slice(0, 150) + (userAndAssistantMessages.length > 3 ? "..." : "");

    const session: SavedSession = {
      id: conversation.id,
      name: conversation.name,
      created_at: conversation.createdAt.toISOString(),
      last_activity_at: conversation.lastActivityAt.toISOString(),
      working_directory: conversation.workingDirectory,
      message_count: conversation.terminalLines.length,
      preview: previewContent || "Empty conversation",
      messages,
    };

    try {
      await invoke("save_session", { session });
      await loadSessions();
    } catch (error) {
      console.error("Failed to save session:", error);
    }
  }

  async function loadSession(sessionId: string): Promise<SavedSession | null> {
    try {
      const session = await invoke<SavedSession | null>("load_session", {
        sessionId,
      });
      return session;
    } catch (error) {
      console.error("Failed to load session:", error);
      return null;
    }
  }

  async function deleteSession(sessionId: string): Promise<void> {
    try {
      await invoke("delete_session", { sessionId });
      await loadSessions();
    } catch (error) {
      console.error("Failed to delete session:", error);
    }
  }

  async function searchSessions(query: string): Promise<void> {
    searchQuery.set(query);

    if (!query.trim()) {
      await loadSessions();
      return;
    }

    isLoading.set(true);
    try {
      const result = await invoke<SessionListItem[]>("search_sessions", {
        query,
      });
      sessions.set(result);
    } catch (error) {
      console.error("Failed to search sessions:", error);
    } finally {
      isLoading.set(false);
    }
  }

  async function clearAllSessions(): Promise<void> {
    try {
      await invoke("clear_all_sessions");
      sessions.set([]);
    } catch (error) {
      console.error("Failed to clear sessions:", error);
    }
  }

  function scheduleAutoSave(conversation: Conversation): void {
    // Don't auto-save empty conversations
    if (conversation.terminalLines.length === 0) {
      return;
    }

    // Clear any pending auto-save for this conversation
    const existingTimeout = pendingAutoSaves.get(conversation.id);
    if (existingTimeout) {
      clearTimeout(existingTimeout);
    }

    // Schedule a new auto-save
    const timeout = setTimeout(async () => {
      pendingAutoSaves.delete(conversation.id);
      try {
        await saveConversation(conversation);
      } catch (error) {
        console.error("Auto-save failed:", error);
      }
    }, AUTO_SAVE_DEBOUNCE_MS);

    pendingAutoSaves.set(conversation.id, timeout);
  }

  function cancelAutoSave(conversationId: string): void {
    const existingTimeout = pendingAutoSaves.get(conversationId);
    if (existingTimeout) {
      clearTimeout(existingTimeout);
      pendingAutoSaves.delete(conversationId);
    }
  }

  async function exportSessionAsJson(sessionId: string): Promise<boolean> {
    try {
      const session = await loadSession(sessionId);
      if (!session) {
        console.error("Session not found for export");
        return false;
      }

      const filePath = await save({
        defaultPath: `hikari-session-${session.name.replace(/[^a-zA-Z0-9]/g, "-")}.json`,
        filters: [{ name: "JSON", extensions: ["json"] }],
      });

      if (!filePath) {
        return false;
      }

      const exportData = {
        version: 1,
        exported_at: new Date().toISOString(),
        session,
      };

      await writeTextFile(filePath, JSON.stringify(exportData, null, 2));
      return true;
    } catch (error) {
      console.error("Failed to export session as JSON:", error);
      return false;
    }
  }

  async function exportSessionAsMarkdown(sessionId: string): Promise<boolean> {
    try {
      const session = await loadSession(sessionId);
      if (!session) {
        console.error("Session not found for export");
        return false;
      }

      const filePath = await save({
        defaultPath: `hikari-session-${session.name.replace(/[^a-zA-Z0-9]/g, "-")}.md`,
        filters: [{ name: "Markdown", extensions: ["md"] }],
      });

      if (!filePath) {
        return false;
      }

      let markdown = `# ${session.name}\n\n`;
      markdown += `**Created:** ${new Date(session.created_at).toLocaleString()}\n`;
      markdown += `**Last Activity:** ${new Date(session.last_activity_at).toLocaleString()}\n`;
      markdown += `**Working Directory:** ${session.working_directory || "Not set"}\n`;
      markdown += `**Messages:** ${session.message_count}\n\n`;
      markdown += `---\n\n`;

      for (const message of session.messages) {
        const timestamp = new Date(message.timestamp).toLocaleTimeString();
        if (message.type === "user") {
          markdown += `## 👤 User (${timestamp})\n\n${message.content}\n\n`;
        } else if (message.type === "assistant") {
          markdown += `## 🤖 Assistant (${timestamp})\n\n${message.content}\n\n`;
        } else if (message.type === "tool_use") {
          markdown += `### 🔧 Tool: ${message.tool_name || "Unknown"} (${timestamp})\n\n\`\`\`\n${message.content}\n\`\`\`\n\n`;
        } else if (message.type === "tool_result") {
          markdown += `### 📋 Result (${timestamp})\n\n\`\`\`\n${message.content}\n\`\`\`\n\n`;
        } else if (message.type === "system") {
          markdown += `> **System:** ${message.content}\n\n`;
        } else if (message.type === "error") {
          markdown += `> ⚠️ **Error:** ${message.content}\n\n`;
        }
      }

      markdown += `---\n\n*Exported from Hikari Desktop*\n`;

      await writeTextFile(filePath, markdown);
      return true;
    } catch (error) {
      console.error("Failed to export session as Markdown:", error);
      return false;
    }
  }

  async function exportSessionAsHtml(
    sessionId: string,
    includeMetadata: boolean = true
  ): Promise<boolean> {
    try {
      const session = await loadSession(sessionId);
      if (!session) {
        console.error("Session not found for export");
        return false;
      }

      const filePath = await save({
        defaultPath: `hikari-session-${session.name.replace(/[^a-zA-Z0-9]/g, "-")}.html`,
        filters: [{ name: "HTML", extensions: ["html"] }],
      });

      if (!filePath) {
        return false;
      }

      const html = generateHtmlExport(session, includeMetadata);
      await writeTextFile(filePath, html);
      return true;
    } catch (error) {
      console.error("Failed to export session as HTML:", error);
      return false;
    }
  }

  async function exportSessionAsPdf(
    sessionId: string,
    includeMetadata: boolean = true
  ): Promise<boolean> {
    try {
      const session = await loadSession(sessionId);
      if (!session) {
        console.error("Session not found for export");
        return false;
      }

      const filePath = await save({
        defaultPath: `hikari-session-${session.name.replace(/[^a-zA-Z0-9]/g, "-")}-print.html`,
        filters: [{ name: "HTML (for PDF printing)", extensions: ["html"] }],
      });

      if (!filePath) {
        return false;
      }

      const html = generatePrintableHtml(session, includeMetadata);
      await writeTextFile(filePath, html);

      // Open the file in the default browser for print-to-PDF
      await openPath(filePath);
      return true;
    } catch (error) {
      console.error("Failed to export session for PDF:", error);
      return false;
    }
  }

  async function importSession(): Promise<boolean> {
    try {
      const filePath = await open({
        filters: [{ name: "JSON", extensions: ["json"] }],
        multiple: false,
      });

      if (!filePath) {
        return false;
      }

      const content = await readTextFile(filePath as string);
      const importData = JSON.parse(content);

      if (!importData.session || !importData.session.id) {
        console.error("Invalid session file format");
        return false;
      }

      const session: SavedSession = importData.session;

      // Generate a new ID to avoid conflicts with existing sessions
      session.id = `imported-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
      session.name = `${session.name} (Imported)`;

      await invoke("save_session", { session });
      await loadSessions();
      return true;
    } catch (error) {
      console.error("Failed to import session:", error);
      return false;
    }
  }

  return {
    sessions: { subscribe: sessions.subscribe },
    isLoading: { subscribe: isLoading.subscribe },
    searchQuery: { subscribe: searchQuery.subscribe },
    loadSessions,
    saveConversation,
    loadSession,
    deleteSession,
    searchSessions,
    clearAllSessions,
    scheduleAutoSave,
    cancelAutoSave,
    exportSessionAsJson,
    exportSessionAsMarkdown,
    exportSessionAsHtml,
    exportSessionAsPdf,
    importSession,
  };
}

export const sessionsStore = createSessionsStore();
