import { onBeforeUnmount } from "vue";
import { Terminal } from "@xterm/xterm";
import { FitAddon } from "@xterm/addon-fit";
import { SearchAddon } from "@xterm/addon-search";
import { WebLinksAddon } from "@xterm/addon-web-links";
import { Call, Events } from "@wailsio/runtime";
import "@xterm/xterm/css/xterm.css";

const SSH = "github.com/vstockwell/wraith/internal/ssh.SSHService";

/** MobaXTerm Classic–inspired terminal theme colors. */
const defaultTheme = {
  background: "#0d1117",
  foreground: "#e0e0e0",
  cursor: "#58a6ff",
  cursorAccent: "#0d1117",
  selectionBackground: "rgba(88, 166, 255, 0.3)",
  selectionForeground: "#ffffff",
  black: "#0d1117",
  red: "#f85149",
  green: "#3fb950",
  yellow: "#e3b341",
  blue: "#58a6ff",
  magenta: "#bc8cff",
  cyan: "#39c5cf",
  white: "#e0e0e0",
  brightBlack: "#484f58",
  brightRed: "#ff7b72",
  brightGreen: "#56d364",
  brightYellow: "#e3b341",
  brightBlue: "#79c0ff",
  brightMagenta: "#d2a8ff",
  brightCyan: "#56d4dd",
  brightWhite: "#f0f6fc",
};

export interface UseTerminalReturn {
  terminal: Terminal;
  fitAddon: FitAddon;
  mount: (container: HTMLElement) => void;
  destroy: () => void;
  write: (data: string) => void;
  fit: () => void;
}

/**
 * Composable that manages an xterm.js Terminal lifecycle.
 *
 * Wires bidirectional I/O:
 *   - User keystrokes → SSHService.Write (via Wails Call)
 *   - SSH stdout → xterm.js (via Wails Events, base64 encoded)
 *   - Terminal resize → SSHService.Resize (via Wails Call)
 */
export function useTerminal(sessionId: string): UseTerminalReturn {
  const fitAddon = new FitAddon();
  const searchAddon = new SearchAddon();
  const webLinksAddon = new WebLinksAddon();

  const terminal = new Terminal({
    theme: defaultTheme,
    fontFamily: "'JetBrains Mono', 'Cascadia Code', 'Fira Code', Menlo, Monaco, monospace",
    fontSize: 14,
    lineHeight: 1.2,
    cursorBlink: true,
    cursorStyle: "block",
    scrollback: 10000,
    allowProposedApi: true,
    convertEol: true,
  });

  terminal.loadAddon(fitAddon);
  terminal.loadAddon(searchAddon);
  terminal.loadAddon(webLinksAddon);

  // Forward typed data to the SSH backend
  terminal.onData((data: string) => {
    Call.ByName(`${SSH}.Write`, sessionId, data).catch((err: unknown) => {
      console.error("SSH write error:", err);
    });
  });

  // Forward resize events to the SSH backend
  terminal.onResize((size: { cols: number; rows: number }) => {
    Call.ByName(`${SSH}.Resize`, sessionId, size.cols, size.rows).catch((err: unknown) => {
      console.error("SSH resize error:", err);
    });
  });

  // Listen for SSH output events from the Go backend (base64 encoded)
  let cleanupEvent: (() => void) | null = null;

  let resizeObserver: ResizeObserver | null = null;

  function mount(container: HTMLElement): void {
    terminal.open(container);
    fitAddon.fit();

    // Subscribe to SSH output events for this session
    cleanupEvent = Events.On(`ssh:data:${sessionId}`, (...args: unknown[]) => {
      // Wails v3 events pass data as arguments
      const b64data = typeof args[0] === "string" ? args[0] : String(args[0] ?? "");
      try {
        const decoded = atob(b64data);
        terminal.write(decoded);
      } catch {
        // Fallback: write raw if not valid base64
        terminal.write(b64data);
      }
    });

    // Auto-fit when the container resizes
    resizeObserver = new ResizeObserver(() => {
      fitAddon.fit();
    });
    resizeObserver.observe(container);
  }

  function destroy(): void {
    if (cleanupEvent) {
      cleanupEvent();
      cleanupEvent = null;
    }
    if (resizeObserver) {
      resizeObserver.disconnect();
      resizeObserver = null;
    }
    terminal.dispose();
  }

  function write(data: string): void {
    terminal.write(data);
  }

  function fit(): void {
    fitAddon.fit();
  }

  onBeforeUnmount(() => {
    destroy();
  });

  return { terminal, fitAddon, mount, destroy, write, fit };
}
