import { createRequire } from "module";
const require = createRequire(import.meta.url);

const NodeMediaServer = require("node-media-server");
const { randomBytes } = require("crypto");
import path from "path";

let nms: any = null;
let isRunning = false;
const activeStreams = new Map<number, string>();

const config = {
  rtmp: {
    port: 1935,
    chunk_size: 60000,
    gop_cache: true,
    ping: 30,
    ping_timeout: 60,
    listen: "0.0.0.0", // Bind to all interfaces
  },
  http: {
    port: 8001,
    mediaroot: path.join(process.cwd(), "media"),
    allow_origin: "*",
  },
};

function generateStreamKey() {
  return randomBytes(16).toString("hex");
}

export function startRTMPServer() {
  try {
    if (isRunning && nms) {
      console.log("[RTMP] Server is already running");
      return true;
    }

    console.log("[RTMP] Starting server...");
    nms = new NodeMediaServer(config);

    // Use property-based event assignment (NodeMediaServer v4+)
    nms.onPrePublish = async (id: string, streamPath: string, args: any) => {
      try {
        const streamKey = streamPath.split("/")[2];
        console.log(`[RTMP] Stream started with key: ${streamKey}`);
        if (!isNaN(Number(streamKey))) {
          activeStreams.set(Number(streamKey), id);
        }
      } catch (error) {
        console.error("[RTMP] Error in onPrePublish:", error);
      }
    };

    nms.onDonePublish = async (id: string, streamPath: string, args: any) => {
      try {
        const streamKey = streamPath.split("/")[2];
        console.log(`[RTMP] Stream ended with key: ${streamKey}`);
        if (!isNaN(Number(streamKey))) {
          activeStreams.delete(Number(streamKey));
        }
      } catch (error) {
        console.error("[RTMP] Error in onDonePublish:", error);
      }
    };

    nms.onError = (err: any) => {
      console.error("[RTMP] Server Error:", err);
      isRunning = false;
    };

    nms.run();
    isRunning = true;
    console.log("[RTMP] Server started on port", config.rtmp.port);
    return true;
  } catch (error) {
    console.error("[RTMP] Error starting server:", error);
    isRunning = false;
    nms = null;
    return false;
  }
}

export function stopRTMPServer() {
  if (nms && isRunning) {
    try {
      nms.stop();
      isRunning = false;
      nms = null;
      activeStreams.clear();
      console.log("[RTMP] Server stopped");
      return true;
    } catch (error) {
      console.error("[RTMP] Error stopping server:", error);
      isRunning = false;
      nms = null;
      return false;
    }
  }
  return false;
}

export function isRTMPServerRunning(): boolean {
  return isRunning && nms !== null;
}

export function getRTMPUrl(sessionId: number): string {
  const baseURL = process.env.RTMP_SERVER_URL || "rtmp://localhost";
  return `${baseURL}/live/${sessionId}`;
}

export function isStreamActive(sessionId: number): boolean {
  try {
    if (!nms || !isRunning) {
      console.log("[RTMP] Server not running, returning false");
      return false;
    }

    // Check in our activeStreams map first
    if (activeStreams.has(sessionId)) {
      console.log(`[RTMP] Found active stream for session ${sessionId} in activeStreams map`);
      return true;
    }

    // Get active clients from node-media-server
    const clients = nms.clients;
    if (!clients) {
      console.log("[RTMP] No clients object available");
      return false;
    }

    // The stream path we're looking for
    const streamPath = `/live/${sessionId}`;

    // Check all active publishers
    for (let id in clients) {
      const client = clients[id];
      if (client && client.publishing && client.publishStreamPath === streamPath) {
        console.log(`[RTMP] Found active publisher for session ${sessionId}`);
        // Update our map if we found an active stream
        activeStreams.set(sessionId, id);
        return true;
      }
    }

    console.log(`[RTMP] No active stream found for session ${sessionId}`);
    return false;
  } catch (error) {
    console.error(`[RTMP] Error checking stream status for session ${sessionId}:`, error);
    return false;
  }
}