import "server-only";

import AsteriskManager from "asterisk-manager";
import { EventEmitter } from "events";
import env from "@/env";
import type { AmiEvent, AmiActionResult, ContactInfo, EndpointLatencyData } from "@/types/ami-events";

/**
 * Interfaz para eventos AMI con propiedades comunes
 */
interface AmiManagerEvent {
  event?: string;
  objectname?: string;
  endpointname?: string;
  endpoint?: string;
  uri?: string;
  status?: string;
  roundtripusec?: string | number;
  [key: string]: unknown;
}

/**
 * Tipo para event listeners de AMI
 */
type AmiEventListener = (...args: unknown[]) => void;

// EventEmitter para desacoplar el cliente AMI de las respuestas HTTP (SSE)
export const amiEvents = new EventEmitter();

let ami: AsteriskManager | null = null;
let isConnected = false;

function initializeAmi() {
  if (ami) {
    console.log("AMI Manager ya está inicializado.");
    return ami;
  }

  console.log(`Intentando conectar a AMI en ${env.AMI_HOST}:${env.AMI_PORT}`);

  ami = new AsteriskManager(
    env.AMI_PORT,
    env.AMI_HOST,
    env.AMI_USERNAME,
    env.AMI_PASSWORD,
    true,
  );

  // Mantiene la conexión activa y reconecta si se cae
  ami.keepConnected();

  ami.on("connect", () => {
    isConnected = true;
    console.log("Conectado a Asterisk Manager Interface.");
    amiEvents.emit("amiEvent", { event: "AmiConnected" });
  });

  ami.on("disconnect", () => {
    isConnected = false;
    console.log("Desconectado de Asterisk Manager Interface.");
    amiEvents.emit("amiEvent", { event: "AmiDisconnected" });
  });

  ami.on("managerevent", (evt: AmiManagerEvent) => {
    // Emitimos el evento para que otros módulos (como la ruta SSE) lo escuchen
    amiEvents.emit("amiEvent", evt);
  });

  ami.on("error", (err: Error) => {
    console.error("Error en AMI Manager:", err);
  });

  return ami;
}

// Función para obtener la instancia del cliente AMI
export const getAmiClient = () => {
  if (!ami) {
    return initializeAmi();
  }
  return ami;
};

// Función para verificar el estado de la conexión
export const isAmiConnected = () => isConnected;

// Ejecuta una acción AMI tipada de forma segura
export async function executeAmiAction(
  action: string,
  params: Record<string, string | number | boolean>,
): Promise<AmiActionResult> {
  try {
    const client = getAmiClient();
    return await new Promise((resolve) => {
      client.action({ action, ...params }, (err: Error | null, res?: Record<string, unknown>) => {
        if (err) return resolve({ success: false, error: String(err) });
        resolve({ success: true, data: res });
      });
    });
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : "Unknown error",
    };
  }
}

// Obtiene información detallada de un endpoint PJSIP incluyendo latencia
export async function getPJSIPEndpointDetails(endpoint: string): Promise<AmiActionResult<{
  endpoint: Record<string, unknown>;
  contacts: ContactInfo[];
}>> {
  try {
    const client = getAmiClient();
    
    return await new Promise((resolve) => {
      const _events: AmiEvent[] = [];
      let _endpointDetail: Record<string, unknown> | null = null;
      const contacts: ContactInfo[] = [];
      
      // Listener temporal para capturar los eventos
      const eventListener = (evt: AmiManagerEvent) => {
        if (evt.event === "EndpointDetail" && evt.objectname === endpoint) {
          _endpointDetail = evt as Record<string, unknown>;
        } else if (evt.event === "ContactStatusDetail" && evt.endpointname === endpoint) {
          const roundtripValue = evt.roundtripusec ? String(evt.roundtripusec) : undefined;
          const contact: ContactInfo = {
            uri: String(evt.uri ?? ""),
            status: String(evt.status ?? "Unknown"),
            roundtripUsec: roundtripValue ? parseInt(roundtripValue, 10) : undefined,
            roundtripMs: roundtripValue ? parseFloat(roundtripValue) / 1000 : undefined,
          };
          contacts.push(contact);
        } else if (evt.event === "EndpointDetailComplete" && evt.endpoint === endpoint) {
          // Remover el listener temporal
          client.removeListener("managerevent", eventListener as AmiEventListener);
          
          resolve({
            success: true,
            data: {
              endpoint: _endpointDetail ?? {},
              contacts: contacts,
            },
          });
        }
      };
      
      // Agregar listener temporal
      client.on("managerevent", eventListener);
      
      // Ejecutar el comando AMI
      client.action(
        {
          action: "PJSIPShowEndpoint",
          endpoint: endpoint,
        },
        (_err: Error | null, _res?: Record<string, unknown>) => {
          if (_err) {
            client.removeListener("managerevent", eventListener as AmiEventListener);
            resolve({ success: false, error: String(_err) });
          }
          // La respuesta llegará a través de los eventos
        }
      );
      
      // Timeout de seguridad
      setTimeout(() => {
        client.removeListener("managerevent", eventListener as AmiEventListener);
        resolve({ success: false, error: "Timeout waiting for endpoint details" });
      }, 10000);
    });
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : "Unknown error",
    };
  }
}

// Obtiene la latencia de todos los endpoints registrados
export async function getAllEndpointsLatency(): Promise<AmiActionResult<Record<string, EndpointLatencyData>>> {
  try {
    const client = getAmiClient();
    
    return await new Promise((resolve) => {
      const endpointsLatency: Record<string, EndpointLatencyData> = {};
      
      // Listener temporal para capturar los eventos
      const eventListener = (evt: AmiManagerEvent) => {
        if (evt.event === "ContactStatusDetail" && evt.endpointname) {
          const endpointName = String(evt.endpointname);
          const roundtripValue = evt.roundtripusec ? String(evt.roundtripusec) : undefined;
          const latencyMs = roundtripValue
            ? parseFloat((parseInt(roundtripValue) / 1000).toFixed(3))
            : undefined;
            
          endpointsLatency[endpointName] = {
            latencyMs,
            status: String(evt.status ?? "Unknown"),
          };
        } else if (evt.event === "ContactStatusDetailComplete") {
          // Remover el listener temporal
          client.removeListener("managerevent", eventListener as AmiEventListener);
          
          resolve({
            success: true,
            data: endpointsLatency,
          });
        }
      };
      
      // Agregar listener temporal
      client.on("managerevent", eventListener);
      
      // Ejecutar el comando AMI para obtener todos los contactos
      client.action(
        {
          action: "PJSIPShowRegistrationInboundContactStatuses",
        },
        (_err: Error | null, _res?: Record<string, unknown>) => {
          if (_err) {
            client.removeListener("managerevent", eventListener as AmiEventListener);
            resolve({ success: false, error: String(_err) });
          }
          // La respuesta llegará a través de los eventos
        }
      );
      
      // Timeout de seguridad
      setTimeout(() => {
        client.removeListener("managerevent", eventListener as AmiEventListener);
        resolve({ success: true, data: endpointsLatency });
      }, 15000);
    });
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : "Unknown error",
    };
  }
}