import { NextResponse } from "next/server";
import { amiEvents, getAmiClient, isAmiConnected } from "@/lib/ami-manager";

export const dynamic = "force-dynamic";

interface AmiEventData {
  event?: string;
  actionid?: string;
  [key: string]: unknown;
}

function collectByActionId(actionId: string, completeEvent: string): Promise<AmiEventData[]> {
  return new Promise<AmiEventData[]>((resolve) => {
    const buffer: AmiEventData[] = [];
    const handler = (evt: AmiEventData) => {
      if (evt?.actionid !== actionId) return;
      if (evt?.event === completeEvent) {
        amiEvents.removeListener("amiEvent", handler);
        resolve(buffer);
        return;
      }
      buffer.push(evt);
    };
    amiEvents.on("amiEvent", handler);
  });
}

// Extrae un objeto plano con todas las claves/valores del evento, excluyendo metadatos AMI
function stripMeta(evt: Record<string, unknown>): Record<string, unknown> {
  const omit = new Set([
    "event",
    "actionid",
    "privilege",
    "systemname",
    "timestamp",
  ]);
  const out: Record<string, unknown> = {};
  for (const [k, v] of Object.entries(evt)) {
    if (!omit.has(k)) out[k] = v;
  }
  return out;
}

interface AmiActionResponse {
  actionid?: string;
  [key: string]: unknown;
}

export async function GET(request: Request): Promise<NextResponse> {
  try {
    const { searchParams } = new URL(request.url);
    const endpoint = searchParams.get("endpoint") ?? searchParams.get("peer");
    if (!endpoint) {
      return NextResponse.json(
        { success: false, error: "Falta query 'endpoint' o 'peer'" },
        { status: 400 },
      );
    }

    const ami = getAmiClient();
    if (!isAmiConnected()) {
      return NextResponse.json(
        { success: false, error: "AMI no conectado" },
        { status: 503 },
      );
    }

    const details = await new Promise<{ grouped: Record<string, unknown[]>; contacts: Record<string, unknown[]> }>(async (resolve) => {
      ami.action({ action: "PJSIPShowEndpoint", endpoint }, async (err: Error | null, res: AmiActionResponse) => {
        if (err || !res?.actionid) return resolve({ grouped: {}, contacts: {} });
        const events = await collectByActionId(String(res.actionid), "EndpointDetailComplete");

        const grouped: Record<string, unknown[]> = {
          EndpointDetail: [],
          AorDetail: [],
          AuthDetail: [],
          TransportDetail: [],
          IdentifyDetail: [],
        };

        for (const e of events) {
          const eventType = String(e.event ?? "");
          if (grouped.hasOwnProperty(eventType)) {
            grouped[eventType].push(stripMeta(e as Record<string, unknown>));
          }
        }

        // Intentar obtener contactos por cada AOR asociado
        const aorDetail = grouped.AorDetail ?? [];
        const aors: string[] = Array.from(
          new Set(
            aorDetail
              .map((a) => {
                const obj = a as Record<string, unknown>;
                const value = obj.ObjectName ?? obj.objectname ?? obj.Aor ?? obj.aor;
                return typeof value === 'string' ? value : '';
              })
              .filter(Boolean),
          ),
        );

        const contacts: Record<string, unknown[]> = {};
        for (const aor of aors) {
          // Algunos sistemas usan PJSIPShowContacts, otros PJSIPShowAors para detalles; probamos contactos primero
          await new Promise<void>((resolveContacts) => {
            ami.action({ action: "PJSIPShowContacts", aor }, async (cerr: Error | null, cres: AmiActionResponse) => {
              if (cerr || !cres?.actionid) {
                contacts[aor] = [];
                return resolveContacts();
              }
              const cevents = await collectByActionId(String(cres.actionid), "ContactListComplete");
              contacts[aor] = cevents
                .filter((x) => x?.event === "ContactDetail" || x?.event === "ContactStatus")
                .map((x) => stripMeta(x as Record<string, unknown>));
              resolveContacts();
            });
          });
        }

        resolve({ grouped, contacts });
      });
    });

    // console.log(JSON.stringify(details, null, 2));  

    return NextResponse.json({ success: true, endpoint, ...details });
  } catch (error) {
    console.error("[AMI endpoint-details] Error:", error);
    return NextResponse.json(
      { success: false, error: "Error interno obteniendo detalles del endpoint" },
      { status: 500 },
    );
  }
}