import { NextResponse } from "next/server";
import { isPortalBroadcastEvent } from "@open-mercato/shared/modules/events";
import { getCustomerAuthFromRequest } from "@open-mercato/core/modules/customer_accounts/lib/customerAuth";
const metadata = { requireAuth: false };
const HEARTBEAT_INTERVAL_MS = 3e4;
const MAX_PAYLOAD_BYTES = 4096;
function normalizeAudience(data) {
  const tenantId = typeof data.tenantId === "string" ? data.tenantId : null;
  const organizationScopes = /* @__PURE__ */ new Set();
  if (typeof data.organizationId === "string" && data.organizationId.trim().length > 0) {
    organizationScopes.add(data.organizationId.trim());
  }
  if (Array.isArray(data.organizationIds)) {
    for (const orgId of data.organizationIds) {
      if (typeof orgId === "string" && orgId.trim().length > 0) {
        organizationScopes.add(orgId.trim());
      }
    }
  }
  const recipientUserScopes = /* @__PURE__ */ new Set();
  if (typeof data.recipientUserId === "string" && data.recipientUserId.trim().length > 0) {
    recipientUserScopes.add(data.recipientUserId.trim());
  }
  if (Array.isArray(data.recipientUserIds)) {
    for (const userId of data.recipientUserIds) {
      if (typeof userId === "string" && userId.trim().length > 0) {
        recipientUserScopes.add(userId.trim());
      }
    }
  }
  return {
    tenantId,
    organizationScopes: Array.from(organizationScopes),
    recipientUserScopes: Array.from(recipientUserScopes)
  };
}
function matchesAudience(conn, audience) {
  if (!audience.tenantId) return false;
  if (conn.tenantId !== audience.tenantId) return false;
  if (audience.organizationScopes.length > 0) {
    if (!audience.organizationScopes.includes(conn.organizationId)) return false;
  }
  if (audience.recipientUserScopes.length > 0 && !audience.recipientUserScopes.includes(conn.customerUserId)) {
    return false;
  }
  return true;
}
const portalConnections = /* @__PURE__ */ new Set();
let portalTapRegistered = false;
async function broadcastPortalEvent(eventName, payload) {
  if (!eventName || portalConnections.size === 0) return;
  if (!isPortalBroadcastEvent(eventName)) return;
  const data = payload ?? {};
  const audience = normalizeAudience(data);
  const organizationId = audience.organizationScopes[0] ?? "";
  let ssePayload = JSON.stringify({
    id: eventName,
    payload: data,
    timestamp: Date.now(),
    organizationId
  });
  if (new TextEncoder().encode(ssePayload).length > MAX_PAYLOAD_BYTES) {
    const entityRef = { truncated: true };
    if (typeof data.id === "string" && data.id.trim().length > 0) entityRef.id = data.id.trim();
    if (typeof data.entityId === "string" && data.entityId.trim().length > 0) entityRef.entityId = data.entityId.trim();
    ssePayload = JSON.stringify({
      id: eventName,
      payload: entityRef,
      timestamp: Date.now(),
      organizationId
    });
    if (new TextEncoder().encode(ssePayload).length > MAX_PAYLOAD_BYTES) {
      return;
    }
  }
  for (const conn of portalConnections) {
    if (!matchesAudience(conn, audience)) continue;
    try {
      conn.send(ssePayload);
    } catch {
    }
  }
}
function ensurePortalTap() {
  if (portalTapRegistered) return;
  portalTapRegistered = true;
  import("@open-mercato/events/bus").then(({ registerGlobalEventTap, registerCrossProcessEventListener }) => {
    registerGlobalEventTap(async (eventName, payload) => {
      await broadcastPortalEvent(eventName, payload ?? {});
    });
    registerCrossProcessEventListener(async (envelope) => {
      if (envelope.originPid === process.pid) return;
      await broadcastPortalEvent(
        envelope.event,
        envelope.payload ?? {}
      );
    });
  }).catch(() => {
    portalTapRegistered = false;
  });
}
async function GET(req) {
  const auth = await getCustomerAuthFromRequest(req);
  if (!auth) {
    return NextResponse.json({ ok: false, error: "Authentication required" }, { status: 401 });
  }
  ensurePortalTap();
  const encoder = new TextEncoder();
  let heartbeatTimer = null;
  let connection = null;
  const onAbort = () => cleanup();
  const stream = new ReadableStream({
    start(controller) {
      const send = (data) => {
        controller.enqueue(encoder.encode(`data: ${data}

`));
      };
      connection = {
        tenantId: auth.tenantId,
        organizationId: auth.orgId,
        customerUserId: auth.sub,
        send,
        close: () => controller.close()
      };
      portalConnections.add(connection);
      controller.enqueue(encoder.encode(": connected\n\n"));
      heartbeatTimer = setInterval(() => {
        try {
          controller.enqueue(encoder.encode(":heartbeat\n\n"));
        } catch {
        }
      }, HEARTBEAT_INTERVAL_MS);
    },
    cancel() {
      cleanup();
    }
  });
  function cleanup() {
    if (heartbeatTimer) {
      clearInterval(heartbeatTimer);
      heartbeatTimer = null;
    }
    if (connection) {
      portalConnections.delete(connection);
      connection = null;
    }
    req.signal.removeEventListener("abort", onAbort);
  }
  req.signal.addEventListener("abort", onAbort, { once: true });
  return new Response(stream, {
    status: 200,
    headers: {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache, no-transform",
      "Connection": "keep-alive",
      "X-Accel-Buffering": "no"
    }
  });
}
const methodDoc = {
  summary: "Subscribe to portal events via SSE (Portal Event Bridge)",
  description: "Long-lived SSE connection that receives server-side events marked with portalBroadcast: true. Events are filtered by the customer's tenant, organization, and recipient user audience.",
  tags: ["Customer Portal"],
  responses: [
    {
      status: 200,
      description: "Event stream (text/event-stream)"
    }
  ],
  errors: [
    { status: 401, description: "Not authenticated" }
  ]
};
const openApi = {
  summary: "Portal event stream",
  methods: { GET: methodDoc }
};
export {
  GET,
  metadata,
  openApi
};
//# sourceMappingURL=stream.js.map
