// Toast notification system for backend errors
// Displays toast notifications at the top of the page

type ToastType = "error" | "success" | "info";

const TOAST_DEFAULT_DURATION = 5000;

// Create toast container
const createToastContainer = (): HTMLElement => {
  let container = document.getElementById("toast-container");
  if (!container) {
    container = document.createElement("div");
    container.id = "toast-container";
    container.className =
      "fixed top-5 right-5 z-[9999] flex flex-col gap-2.5 pointer-events-none";
    document.body.appendChild(container);
  }
  return container;
};

// Escape HTML to prevent XSS
const toastEscapeHtml = (text: string): string => {
  const div = document.createElement("div");
  div.textContent = text;
  return div.innerHTML;
};

// Get toast configuration by type
const getToastConfig = (type: ToastType) => {
  const configs = {
    error: {
      bgClass: "bg-red-500/90",
      icon: "❌",
    },
    success: {
      bgClass: "bg-green-500/90",
      icon: "✅",
    },
    info: {
      bgClass: "bg-blue-500/90",
      icon: "ℹ️",
    },
  };
  return configs[type];
};

// Create a toast element
const createToastElement = (message: string, type: ToastType): HTMLElement => {
  const toast = document.createElement("div");
  const config = getToastConfig(type);

  toast.className = `${config.bgClass} text-white p-4 rounded-lg shadow-lg flex items-center gap-3 min-w-[300px] max-w-[500px] text-sm leading-relaxed pointer-events-auto opacity-0 -translate-y-5 transition-all duration-300 border border-white/10`;

  toast.innerHTML = `
        <span class="text-xl flex-shrink-0">${config.icon}</span>
        <span class="flex-1 break-words">${toastEscapeHtml(message)}</span>
        <button class="toast-close bg-transparent border-0 text-white cursor-pointer text-lg p-0 w-5 h-5 flex items-center justify-center opacity-70 hover:opacity-100 flex-shrink-0 transition-opacity">
            ×
        </button>
    `;

  // Add close button handler
  const closeBtn = toast.querySelector(".toast-close") as HTMLElement;
  if (closeBtn) {
    closeBtn.onclick = () => removeToast(toast);
  }

  return toast;
};

// Trigger toast animation
const animateToastIn = (toast: HTMLElement): void => {
  setTimeout(() => {
    toast.style.opacity = "1";
    toast.style.transform = "translateY(0)";
  }, 10);
};

// Remove toast with animation
const removeToast = (toast: HTMLElement): void => {
  toast.style.opacity = "0";
  toast.style.transform = "translateY(-20px)";
  setTimeout(() => {
    if (toast.parentElement) {
      toast.parentElement.removeChild(toast);
    }
  }, 300);
};

// Show toast notification
const showToast = (
  message: string,
  type: ToastType,
  duration: number = TOAST_DEFAULT_DURATION,
): void => {
  const container = createToastContainer();
  const toast = createToastElement(message, type);
  container.appendChild(toast);
  animateToastIn(toast);

  // Auto-remove after duration
  setTimeout(() => {
    removeToast(toast);
  }, duration);
};

// Parse error from XHR response
const parseXHRError = (xhr: XMLHttpRequest): string => {
  let errorMessage = "An error occurred";
  try {
    const response = JSON.parse(xhr.responseText);
    errorMessage = response.error || response.message || errorMessage;
  } catch (e) {
    errorMessage = xhr.responseText || errorMessage;
  }
  return errorMessage;
};

// Parse error from fetch response
const parseFetchError = async (response: Response): Promise<string> => {
  const contentType = response.headers.get("content-type");
  if (contentType && contentType.includes("application/json")) {
    const data = await response.json();
    return data.error || data.message || `Error ${response.status}`;
  }
  return `Error ${response.status}: ${response.statusText}`;
};

// Setup HTMX error listeners
const setupHTMXListeners = (): void => {
  // Listen for HTMX afterSwap event to detect errors in swapped content
  document.body.addEventListener("htmx:afterSwap", (evt: Event) => {
    interface HTMXEventDetail {
      xhr: XMLHttpRequest;
      succeeded: boolean;
      target: Element;
    }

    const customEvent = evt as CustomEvent<HTMXEventDetail>;

    if (customEvent.detail.xhr) {
      const xhr = customEvent.detail.xhr;

      if (
        customEvent.detail.succeeded === false &&
        xhr.status >= 400 &&
        xhr.status < 600
      ) {
        const errorMessage = parseXHRError(xhr);
        showToast(errorMessage, "error");
      } else if (xhr.status >= 200 && xhr.status < 300) {
        const contentType = xhr.getResponseHeader("content-type");
        if (contentType && contentType.includes("application/json")) {
          try {
            const response = JSON.parse(xhr.responseText);
            if (response.message) {
              showToast(response.message, "success");
              if (customEvent.detail.target) {
                customEvent.detail.target.innerHTML = "";
              }
            }
          } catch (e) {
            // Not valid JSON — ignore
          }
        }
      }
    }
  });

  // Also listen for response errors (network issues, invalid responses)
  document.body.addEventListener("htmx:responseError", (evt: Event) => {
    const customEvent = evt as CustomEvent<{ xhr: XMLHttpRequest }>;
    const xhr = customEvent.detail.xhr;
    const errorMessage = parseXHRError(xhr);
    showToast(errorMessage, "error");
  });
};

// Setup fetch interceptor
const setupFetchInterceptor = (): void => {
  const originalFetch = window.fetch;
  window.fetch = async (
    ...args: Parameters<typeof fetch>
  ): Promise<Response> => {
    try {
      const response = await originalFetch(...args);

      // Special handling for 401 Unauthorized
      if (response.status === 401) {
        // Clear invalid tokens from localStorage
        localStorage.removeItem("token");
        localStorage.removeItem("refreshToken");
        localStorage.removeItem("user");

        // Check if this was a page navigation (not API call)
        const url = args[0] as string;

        // Don't show toast for page navigations - will be handled by redirect
        if (!url.startsWith("/api/")) {
          // Direct navigation to protected page will be caught by middleware
          // Just throw to prevent further processing
          throw new Error("Session expired");
        }

        // API call - show toast error
        const errorMessage = await parseFetchError(response);
        showToast(errorMessage, "error");

        return response;
      }

      // Handle other errors
      if (!response.ok) {
        const errorMessage = await parseFetchError(response);
        showToast(errorMessage, "error");
      }

      return response;
    } catch (error) {
      // Don't show toast for redirect errors
      if ((error as Error).message !== "Session expired") {
        showToast("Network error: Unable to connect to server", "error");
      }
      throw error;
    }
  };
};

// Initialize toast system
const initializeToastSystem = (): void => {
  setupHTMXListeners();
  setupFetchInterceptor();
};

initializeToastSystem();

export { showToast };
export type { ToastType };
