import { getApiUrl } from "../env";
import { apiFetch } from "./auth";

export interface ConsoleTokenResponse {
  token: string;
  expiresAt: string;
}

export interface ConsoleWebSocketHandlers {
  onOpen?: () => void;
  onClose?: (event: CloseEvent) => void;
  onError?: (event: Event) => void;
  onLine?: (line: string, stream?: string) => void;
}

interface ConsoleLogMessage {
  type?: string;
  line?: string;
  stream?: string;
  message?: string;
}

function getConsoleWebSocketUrl(serverId: string, token: string): string {
  const apiUrl = new URL(getApiUrl());
  apiUrl.protocol = apiUrl.protocol === "https:" ? "wss:" : "ws:";
  const basePath = apiUrl.pathname.replace(/\/$/, "");
  apiUrl.pathname = `${basePath}/servers/${serverId}/console/ws`;
  apiUrl.search = new URLSearchParams({ token }).toString();
  return apiUrl.toString();
}

export async function getConsoleToken(serverId: string): Promise<ConsoleTokenResponse> {
  return apiFetch<ConsoleTokenResponse>(`/servers/${serverId}/console/token`);
}

export function createConsoleWebSocket(
  serverId: string,
  token: string,
  handlers: ConsoleWebSocketHandlers,
): WebSocket {
  const socket = new WebSocket(getConsoleWebSocketUrl(serverId, token));

  socket.addEventListener("open", () => {
    handlers.onOpen?.();
  });

  socket.addEventListener("close", (event) => {
    handlers.onClose?.(event);
  });

  socket.addEventListener("error", (event) => {
    handlers.onError?.(event);
  });

  socket.addEventListener("message", (event) => {
    const raw = typeof event.data === "string" ? event.data : "";

    try {
      const parsed = JSON.parse(raw) as ConsoleLogMessage;
      if (parsed.type === "log" && parsed.line) {
        handlers.onLine?.(parsed.line, parsed.stream);
        return;
      }
      if (parsed.line) {
        handlers.onLine?.(parsed.line, parsed.stream);
        return;
      }
      if (parsed.message) {
        handlers.onLine?.(parsed.message, parsed.stream);
        return;
      }
    } catch {
      // Plain text log line
    }

    if (raw) {
      handlers.onLine?.(raw);
    }
  });

  return socket;
}

export function sendConsoleCommand(socket: WebSocket, command: string): void {
  socket.send(JSON.stringify({ command }));
}
