import { io, Socket } from "socket.io-client";

class WebSocketService {
  private socket: Socket | null = null;
  private reconnectAttempts = 0;
  private maxReconnectAttempts = 5;

  private toWsUrl(base: string) {
    if (!base) return base;
    if (base.startsWith("ws://") || base.startsWith("wss://")) return base;

    try {
      const url = new URL(
        base,
        typeof window !== "undefined"
          ? window.location.origin
          : "http://localhost:3000"
      );
      url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
      return url.toString();
    } catch (err) {
      console.warn("Failed to build WS URL, falling back to base", err);
      return base;
    }
  }

  connect(url?: string) {
    const envWs = process.env.NEXT_PUBLIC_WATCH_FINISHED_WS;
    const envApi = process.env.NEXT_PUBLIC_WATCH_FINISHED_API;
    const isBrowser = typeof window !== "undefined";
    const hostIsLocal =
      !isBrowser ||
      window.location.hostname === "localhost" ||
      window.location.hostname === "127.0.0.1";
    const envApiIsLocal =
      envApi?.includes("localhost") || envApi?.includes("127.0.0.1");

    // Prefer explicit WS host; otherwise use API host (converted to ws/wss).
    // If API host is localhost but the page is remote, fall back to current origin (allows reverse proxy handling).
    const baseUrl =
      url ||
      envWs ||
      (envApi && !(envApiIsLocal && !hostIsLocal) ? envApi : undefined) ||
      (isBrowser ? window.location.origin : "http://localhost:3000");

    const wsUrl = this.toWsUrl(baseUrl);

    if (this.socket?.connected) {
      return this.socket;
    }

    this.socket = io(wsUrl, {
      path: "/socket.io",
      transports: ["websocket", "polling"]
    });

    this.socket.on("connect", () => {
      console.log("Connected to WebSocket server");
      this.reconnectAttempts = 0;
    });

    this.socket.on("disconnect", () => {
      console.log("Disconnected from WebSocket server");
    });

    this.socket.on("connect_error", (error) => {
      console.error("WebSocket connection error:", error);
      this.handleReconnect();
    });

    // Listen for various events
    this.socket.on("taskUpdate", (data) => {
      console.log("Task update:", data);
      // Dispatch custom event for React components
      window.dispatchEvent(new CustomEvent("taskUpdate", { detail: data }));
    });

    this.socket.on("fileUpdate", (data) => {
      console.log("File update:", data);
      window.dispatchEvent(new CustomEvent("fileUpdate", { detail: data }));
    });

    this.socket.on("watcherUpdate", (data) => {
      console.log("Watcher update:", data);
      window.dispatchEvent(new CustomEvent("watcherUpdate", { detail: data }));
    });

    return this.socket;
  }

  disconnect() {
    if (this.socket) {
      this.socket.disconnect();
      this.socket = null;
    }
  }

  joinRoom(room: string) {
    if (this.socket) {
      this.socket.emit("join", { room });
    }
  }

  leaveRoom(room: string) {
    if (this.socket) {
      this.socket.emit("leave", { room });
    }
  }

  private handleReconnect() {
    if (this.reconnectAttempts < this.maxReconnectAttempts) {
      this.reconnectAttempts++;
      setTimeout(() => {
        console.log(
          `Attempting to reconnect... (${this.reconnectAttempts}/${this.maxReconnectAttempts})`
        );
        this.socket?.connect();
      }, 2000 * this.reconnectAttempts); // Exponential backoff
    }
  }

  get isConnected() {
    return this.socket?.connected || false;
  }
}

export const wsService = new WebSocketService();
