"use client";

import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";

export type JetstreamEvent = {
  did: string;
  time_us: number;
  kind: "commit";
  commit: {
    rev: string;
    operation: "create" | "update" | "delete";
    collection: string;
    rkey: string;
    record?: unknown;
    cid?: string;
  };
};

export type JetstreamSubscriber = (event: JetstreamEvent) => void;

const WS_URL = process.env.NEXT_PUBLIC_JETSTREAM_URL || "wss://ws.sidetrail.app";

export class JetstreamClient {
  private ws: WebSocket | null = null;
  private subscribers: Set<JetstreamSubscriber> = new Set();
  private reconnectTimeout: ReturnType<typeof setTimeout> | null = null;
  private shouldReconnect = true;

  connect(): void {
    if (this.ws) return;

    this.ws = new WebSocket(WS_URL);

    this.ws.onopen = () => {};

    this.ws.onmessage = (event) => {
      try {
        const data = JSON.parse(event.data);
        this.handleEvent(data);
      } catch (error) {
        console.error("[Events] Failed to parse event:", error);
      }
    };

    this.ws.onerror = (error) => {
      console.error("[Events] WebSocket error:", error);
    };

    this.ws.onclose = () => {
      this.ws = null;

      if (this.shouldReconnect) {
        this.reconnectTimeout = setTimeout(() => {
          this.connect();
        }, 5000);
      }
    };
  }

  disconnect(): void {
    this.shouldReconnect = false;

    if (this.reconnectTimeout) {
      clearTimeout(this.reconnectTimeout);
      this.reconnectTimeout = null;
    }

    if (this.ws) {
      this.ws.close();
      this.ws = null;
    }
  }

  subscribe(subscriber: JetstreamSubscriber): () => void {
    this.subscribers.add(subscriber);
    return () => {
      this.subscribers.delete(subscriber);
    };
  }

  private handleEvent(event: JetstreamEvent): void {
    this.subscribers.forEach((subscriber) => {
      try {
        subscriber(event);
      } catch (error) {
        console.error("[Events] Subscriber error:", error);
      }
    });
  }

  isConnected(): boolean {
    return this.ws !== null && this.ws.readyState === WebSocket.OPEN;
  }
}

function createSidetrailJetstream(): JetstreamClient {
  return new JetstreamClient();
}

export type JetstreamStatus = "disconnected" | "connecting" | "connected";

let globalClient: JetstreamClient | null = null;

export function useJetstreamInvalidation(
  shouldRefresh: (event: JetstreamEvent) => boolean,
  enabled: boolean = true,
): JetstreamStatus {
  const router = useRouter();
  const [status, setStatus] = useState<JetstreamStatus>("disconnected");

  useEffect(() => {
    if (!enabled) {
      // eslint-disable-next-line react-hooks/set-state-in-effect
      setStatus("disconnected");
      return;
    }

    setStatus("connecting");

    if (!globalClient) {
      globalClient = createSidetrailJetstream();
      globalClient.connect();
    }

    const handleEvent = (event: JetstreamEvent) => {
      if (shouldRefresh(event)) {
        router.refresh();
      }
    };

    const unsubscribe = globalClient.subscribe(handleEvent);

    const checkStatus = () => {
      if (globalClient?.isConnected()) {
        setStatus("connected");
      } else {
        setStatus("connecting");
      }
    };

    checkStatus();
    const statusInterval = setInterval(checkStatus, 1000);

    return () => {
      unsubscribe();
      clearInterval(statusInterval);
      setStatus("disconnected");
    };
  }, [shouldRefresh, enabled, router]);

  return status;
}
