// HTMX-based application initialization
// NOTE: Auth headers are now handled centrally by security-bootstrap.js
(function () {
  "use strict";

  // Configuration
  const config = {
    wsUrl: "/ws",
    apiBase: "/api",
    reconnectDelay: 3000,
    maxReconnectAttempts: 5,
  };

  // State
  let reconnectAttempts = 0;
  let wsConnection = null;

  // Initialize HTMX extensions
  function initHTMX() {
    // Configure HTMX
    htmx.config.defaultSwapStyle = "innerHTML";
    htmx.config.defaultSettleDelay = 100;
    htmx.config.timeout = 10000;

    // Handle errors globally
    document.body.addEventListener("htmx:responseError", (event) => {
      console.error("HTMX Error:", event.detail);
      showNotification("Connection error. Please try again.", "error");
    });

    // Handle before swap to prevent errors when target doesn't exist
    document.body.addEventListener("htmx:beforeSwap", (event) => {
      const target = event.detail.target;
      const status = event.detail.xhr?.status;
      const response = event.detail.serverResponse;
      const swapStyle = event.detail.swapStyle || "innerHTML";

      // If target doesn't exist or response is 404, prevent the swap
      if (!target || status === 404) {
        event.detail.shouldSwap = false;
        console.warn("HTMX swap prevented: target not found or 404 response");
        return;
      }

      // Check if target is actually in the DOM (prevents insertBefore errors)
      if (!document.body.contains(target)) {
        event.detail.shouldSwap = false;
        console.warn("HTMX swap prevented: target not in DOM");
        return;
      }

      // Check if target has a parent (required for most swap operations)
      if (!target.parentNode) {
        event.detail.shouldSwap = false;
        console.warn("HTMX swap prevented: target has no parent");
        return;
      }

      // Additional check: verify parentNode is still in DOM (race condition protection)
      if (
        !document.body.contains(target.parentNode) &&
        target.parentNode !== document.body &&
        target.parentNode !== document.documentElement
      ) {
        event.detail.shouldSwap = false;
        console.warn("HTMX swap prevented: target parent not in DOM");
        return;
      }

      // For swap styles that use insertBefore, verify the parent can accept children
      const insertBasedSwaps = [
        "outerHTML",
        "beforebegin",
        "afterbegin",
        "beforeend",
        "afterend",
      ];
      if (insertBasedSwaps.includes(swapStyle)) {
        try {
          // Verify we can actually perform DOM operations on the target
          if (
            swapStyle === "outerHTML" &&
            (!target.parentNode || !target.parentNode.contains(target))
          ) {
            event.detail.shouldSwap = false;
            console.warn(
              "HTMX swap prevented: outerHTML target detached from parent",
            );
            return;
          }
        } catch (e) {
          event.detail.shouldSwap = false;
          console.warn("HTMX swap prevented: DOM access error", e);
          return;
        }
      }

      // For empty responses, set empty content to prevent insertBefore errors
      if (!response || response.trim() === "") {
        event.detail.serverResponse = "<!-- empty -->";
        return;
      }

      // Validate that response is valid HTML before swapping
      // This prevents "Unexpected end of input" errors
      try {
        const trimmedResponse = response.trim();

        // Skip validation for comments
        if (
          trimmedResponse.startsWith("<!--") &&
          trimmedResponse.endsWith("-->")
        ) {
          return;
        }

        // Try to parse the response as HTML
        const parser = new DOMParser();
        const doc = parser.parseFromString(response, "text/html");

        // Check for parsing errors
        const parseError = doc.querySelector("parsererror");
        if (parseError) {
          console.warn(
            "HTMX swap: Response contains invalid HTML, wrapping in div",
          );
          event.detail.serverResponse = "<div>" + response + "</div>";
        }

        // Check if body is empty (happens with malformed HTML)
        if (
          doc.body &&
          doc.body.children.length === 0 &&
          doc.body.textContent.trim() === ""
        ) {
          if (trimmedResponse.length > 0) {
            console.warn(
              "HTMX swap: Response produced empty DOM, preserving as text",
            );
            event.detail.serverResponse = "<div>" + response + "</div>";
          }
        }
      } catch (e) {
        console.warn("HTMX swap: Error validating response HTML:", e);
        // Wrap potentially malformed content
        event.detail.serverResponse = "<div>" + response + "</div>";
      }
    });

    // Handle swap errors gracefully
    document.body.addEventListener("htmx:swapError", (event) => {
      console.error("HTMX swap error:", event.detail);
      // Don't show notification for swap errors - they're usually timing issues
      // Prevent the error from propagating
      event.preventDefault();
    });

    // Catch any uncaught HTMX errors related to DOM manipulation
    document.body.addEventListener("htmx:afterRequest", (event) => {
      // Clean up any orphaned requests
      const target = event.detail.target;
      if (target && !document.body.contains(target)) {
        console.warn(
          "HTMX afterRequest: target no longer in DOM, cleanup performed",
        );
      }
    });

    // Handle HTMX errors more gracefully
    document.body.addEventListener("htmx:onLoadError", (event) => {
      console.error("HTMX load error:", event.detail);
    });

    // Handle successful swaps
    document.body.addEventListener("htmx:afterSwap", (event) => {
      // Auto-scroll messages if in chat
      const messages = document.getElementById("messages");
      if (messages && event.detail.target === messages) {
        messages.scrollTop = messages.scrollHeight;
      }
    });

    // Handle WebSocket messages
    document.body.addEventListener("htmx:wsMessage", (event) => {
      handleWebSocketMessage(JSON.parse(event.detail.message));
    });

    // Handle WebSocket connection events
    document.body.addEventListener("htmx:wsConnecting", () => {
      updateConnectionStatus("connecting");
    });

    document.body.addEventListener("htmx:wsOpen", () => {
      updateConnectionStatus("connected");
      reconnectAttempts = 0;
    });

    document.body.addEventListener("htmx:wsClose", () => {
      updateConnectionStatus("disconnected");
      attemptReconnect();
    });
  }

  // Handle WebSocket messages
  function handleWebSocketMessage(message) {
    const messageType = message.type || message.event;

    // Debug logging
    console.log("handleWebSocketMessage called with:", { messageType, message });

    // Handle suggestions array from BotResponse
    if (message.suggestions && Array.isArray(message.suggestions) && message.suggestions.length > 0) {
      clearSuggestions();
      message.suggestions.forEach(suggestion => {
        addSuggestionButton(suggestion.text, suggestion.value || suggestion.text);
      });
    }

    switch (messageType) {
      case "message":
        appendMessage(message);
        break;
      case "notification":
        showNotification(message.text, message.severity);
        break;
      case "status":
        updateStatus(message);
        break;
      case "suggestion":
        addSuggestion(message.text);
        break;
      case "change_theme":
        console.log("Processing change_theme event, not appending to chat");
        if (message.data) {
          ThemeManager.setThemeFromServer(message.data);
        }
        return; // Don't append theme events to chat
      default:
        // Only append unknown message types to chat if they have text content
        if (message.text || message.content) {
          console.log("Unknown message type, treating as chat message:", messageType);
          appendMessage(message);
        } else {
          console.log("Unknown message type:", messageType, message);
        }
    }
  }

  // Clear all suggestions
  function clearSuggestions() {
    const suggestionsEl = document.getElementById("suggestions");
    if (suggestionsEl) {
      suggestionsEl.innerHTML = '';
    }
  }

  // Add suggestion button with value
  function addSuggestionButton(text, value) {
    const suggestionsEl = document.getElementById("suggestions");
    if (!suggestionsEl) return;

    const chip = document.createElement("button");
    chip.className = "suggestion-chip";
    chip.textContent = text;
    chip.setAttribute("hx-post", "/api/sessions/current/message");
    chip.setAttribute("hx-vals", JSON.stringify({ content: value }));
    chip.setAttribute("hx-target", "#messages");
    chip.setAttribute("hx-swap", "beforeend");

    suggestionsEl.appendChild(chip);
    htmx.process(chip);
  }

  // Append message to chat
  function appendMessage(message) {
    const messagesEl = document.getElementById("messages");
    if (!messagesEl) return;

    const messageEl = document.createElement("div");
    messageEl.className = `message ${message.sender === "user" ? "user" : "bot"}`;
    messageEl.innerHTML = `
            <div class="message-content">
                <span class="sender">${message.sender}</span>
                <span class="text">${escapeHtml(message.text)}</span>
                <span class="time">${formatTime(message.timestamp)}</span>
            </div>
        `;

    messagesEl.appendChild(messageEl);
    messagesEl.scrollTop = messagesEl.scrollHeight;
  }

  // Add suggestion chip
  function addSuggestion(text) {
    const suggestionsEl = document.getElementById("suggestions");
    if (!suggestionsEl) return;

    const chip = document.createElement("button");
    chip.className = "suggestion-chip";
    chip.textContent = text;
    chip.setAttribute("hx-post", "/api/sessions/current/message");
    chip.setAttribute("hx-vals", JSON.stringify({ content: text }));
    chip.setAttribute("hx-target", "#messages");
    chip.setAttribute("hx-swap", "beforeend");

    suggestionsEl.appendChild(chip);
    htmx.process(chip);
  }

  // Update connection status
  function updateConnectionStatus(status) {
    const statusEl = document.getElementById("connectionStatus");
    if (!statusEl) return;

    statusEl.className = `connection-status ${status}`;
    statusEl.textContent = status.charAt(0).toUpperCase() + status.slice(1);
  }

  // Update general status
  function updateStatus(message) {
    const statusEl = document.getElementById("status-" + message.id);
    if (statusEl) {
      statusEl.textContent = message.text;
      statusEl.className = `status ${message.severity}`;
    }
  }

  // Show notification
  function showNotification(text, type = "info") {
    const notification = document.createElement("div");
    notification.className = `notification ${type}`;
    notification.textContent = text;

    const container = document.getElementById("notifications") || document.body;
    container.appendChild(notification);

    setTimeout(() => {
      notification.classList.add("fade-out");
      setTimeout(() => notification.remove(), 300);
    }, 3000);
  }

  // Attempt to reconnect WebSocket
  function attemptReconnect() {
    if (reconnectAttempts >= config.maxReconnectAttempts) {
      showNotification("Connection lost. Please refresh the page.", "error");
      return;
    }

    reconnectAttempts++;
    setTimeout(() => {
      console.log(`Reconnection attempt ${reconnectAttempts}...`);
      htmx.trigger(document.body, "htmx:wsReconnect");
    }, config.reconnectDelay);
  }

  // Utility: Escape HTML
  function escapeHtml(text) {
    const div = document.createElement("div");
    div.textContent = text;
    return div.innerHTML;
  }

  // Utility: Format timestamp
  function formatTime(timestamp) {
    if (!timestamp) return "";
    const date = new Date(timestamp);
    return date.toLocaleTimeString("en-US", {
      hour: "numeric",
      minute: "2-digit",
      hour12: true,
    });
  }

  // Handle navigation
  function initNavigation() {
    // Update active nav item on page change
    document.addEventListener("htmx:pushedIntoHistory", (event) => {
      const path = event.detail.path;
      updateActiveNav(path);
    });

    // Also listen for htmx:afterSwap to catch all navigation
    document.addEventListener("htmx:afterSwap", (event) => {
      setTimeout(() => {
        const path = window.location.hash || window.location.pathname;
        updateActiveNav(path);
      }, 10);
    });

    // Handle hash change
    window.addEventListener("hashchange", (event) => {
      updateActiveNav(window.location.hash);
    });

    // Handle browser back/forward
    window.addEventListener("popstate", (event) => {
      updateActiveNav(window.location.hash || window.location.pathname);
    });

    // Handle direct clicks on app tabs and app items
    document.addEventListener("click", (event) => {
      const appTab = event.target.closest(".app-tab");
      const appItem = event.target.closest(".app-item");

      if (appTab || appItem) {
        const element = appTab || appItem;
        const href = element.getAttribute("href");
        if (href) {
          // Immediately update active state on click
          updateActiveNav(href);
        }
      }
    });
  }

  // Get current section from URL
  function getCurrentSection() {
    const hash = window.location.hash;
    if (hash && hash.length > 1) {
      // Handle both #section and /#section formats
      return hash.replace(/^#\/?/, "").split("/")[0].split("?")[0];
    }
    return "chat";
  }

  // Update active navigation item and page title
  function updateActiveNav(path) {
    // Extract section name from path
    // Handles: "/#chat", "#chat", "/chat", "chat", "/#paper", "#paper"
    let section;
    if (path && path.length > 0) {
      // Remove leading /, #, or /# combinations
      section = path
        .replace(/^[/#]+/, "")
        .split("/")[0]
        .split("?")[0];
    }

    // Fallback to current URL hash if section is empty
    if (!section) {
      section = getCurrentSection();
    }

    // Set data-app attribute on body for CSS targeting (e.g., docs app styling)
    if (section) {
      document.body.setAttribute("data-app", section);
    }

    // First, remove ALL active classes from all tabs, items, and apps button
    document.querySelectorAll(".app-tab.active").forEach((item) => {
      item.classList.remove("active");
    });
    document.querySelectorAll(".app-item.active").forEach((item) => {
      item.classList.remove("active");
    });

    // Remove active from apps button
    const appsButton = document.getElementById("appsButton");
    if (appsButton) {
      appsButton.classList.remove("active");
    }

    // Check if section exists in the main header tabs
    let foundInHeaderTabs = false;
    document.querySelectorAll(".app-tab").forEach((item) => {
      const dataSection = item.getAttribute("data-section");
      const href = item.getAttribute("href");
      const itemSection = dataSection || (href ? href.replace(/^#/, "") : "");
      if (itemSection === section) {
        item.classList.add("active");
        foundInHeaderTabs = true;
      }
    });

    // Update app items in launcher dropdown (always mark the current section)
    document.querySelectorAll(".app-item").forEach((item) => {
      const href = item.getAttribute("href");
      const dataSection = item.getAttribute("data-section");
      const itemSection = dataSection || (href ? href.replace(/^#/, "") : "");
      if (itemSection === section) {
        item.classList.add("active");
      }
    });

    // If section is NOT in header tabs, select the apps button instead
    if (!foundInHeaderTabs && appsButton) {
      appsButton.classList.add("active");
    }

    // Update page title
    const sectionName = section.charAt(0).toUpperCase() + section.slice(1);
    document.title = sectionName + " - General Bots";
  }

  // Initialize keyboard shortcuts
  function initKeyboardShortcuts() {
    document.addEventListener("keydown", (e) => {
      // Send message on Enter (when in input)
      if (e.key === "Enter" && !e.shiftKey) {
        const input = document.getElementById("messageInput");
        if (input && document.activeElement === input) {
          e.preventDefault();
          const form = input.closest("form");
          if (form) {
            htmx.trigger(form, "submit");
          }
        }
      }

      // Focus input on /
      if (e.key === "/" && document.activeElement.tagName !== "INPUT") {
        e.preventDefault();
        const input = document.getElementById("messageInput");
        if (input) input.focus();
      }

      // Escape to blur input
      if (e.key === "Escape") {
        const input = document.getElementById("messageInput");
        if (input && document.activeElement === input) {
          input.blur();
        }
      }
    });
  }

  // Initialize scroll behavior
  function initScrollBehavior() {
    const scrollBtn = document.getElementById("scrollToBottom");
    const messages = document.getElementById("messages");

    if (scrollBtn && messages) {
      // Show/hide scroll button
      messages.addEventListener("scroll", () => {
        const isAtBottom =
          messages.scrollHeight - messages.scrollTop <=
          messages.clientHeight + 100;
        scrollBtn.style.display = isAtBottom ? "none" : "flex";
      });

      // Scroll to bottom on click
      scrollBtn.addEventListener("click", () => {
        messages.scrollTo({
          top: messages.scrollHeight,
          behavior: "smooth",
        });
      });
    }
  }

  // Initialize theme if ThemeManager exists
  function initTheme() {
    if (window.ThemeManager) {
      ThemeManager.init();
    }
  }

  // Main initialization
  function init() {
    console.log("Initializing HTMX application...");

    // Initialize HTMX
    initHTMX();

    // Initialize navigation
    initNavigation();

    // Initialize keyboard shortcuts
    initKeyboardShortcuts();

    // Initialize scroll behavior
    initScrollBehavior();

    // Initialize theme
    initTheme();

    // Set initial active nav based on hash or default to chat
    updateActiveNav(window.location.hash || "#chat");

    console.log("HTMX application initialized");
  }

  // Wait for DOM and HTMX to be ready
  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }

  // Expose public API
  window.BotServerApp = {
    showNotification,
    appendMessage,
    updateConnectionStatus,
    config,
  };
})();
