const crypto = require("crypto");
const { createLogger } = require("./logger");

const eventLog = createLogger("core:events", { category: "automation" });
const eventTypes = new Map();
const listeners = new Set();

function registerEventType(definition) {
  const id = String(definition?.id || "").trim().toLowerCase();
  if (!/^[a-z0-9]+(?:[._-][a-z0-9]+)*$/.test(id)) throw new Error("Event types require a stable namespaced id.");
  const normalized = Object.freeze({
    id,
    label: String(definition.label || id).trim().slice(0, 120),
    description: String(definition.description || "").trim().slice(0, 500),
    platform: String(definition.platform || id.split(".")[0]).trim().toLowerCase().slice(0, 40),
    supportsTier: Boolean(definition.supportsTier)
  });
  eventTypes.set(id, normalized);
  return () => eventTypes.delete(id);
}

function listEventTypes() {
  return Array.from(eventTypes.values()).sort((left, right) => left.label.localeCompare(right.label));
}

function onLumiEvent(listener) {
  if (typeof listener !== "function") throw new Error("Event listener must be a function.");
  listeners.add(listener);
  return () => listeners.delete(listener);
}

function emitLumiEvent(type, payload = {}, metadata = {}) {
  const eventType = String(type || "").trim().toLowerCase();
  if (!eventTypes.has(eventType)) throw new Error(`Unknown Lumi event type: ${eventType || "empty"}`);
  const event = Object.freeze({
    id: String(metadata.id || crypto.randomUUID()).slice(0, 256),
    type: eventType,
    payload: payload && typeof payload === "object" && !Array.isArray(payload) ? Object.freeze({ ...payload }) : Object.freeze({}),
    source: String(metadata.source || eventType.split(".")[0]).slice(0, 80),
    occurredAt: Number.isFinite(Number(metadata.occurredAt))
      ? Number(metadata.occurredAt)
      : (Number.isFinite(Date.parse(metadata.occurredAt)) ? Date.parse(metadata.occurredAt) : Date.now()),
    test: Boolean(metadata.test)
  });
  for (const listener of listeners) {
    try {
      Promise.resolve(listener(event)).catch((error) => eventLog.error("Event listener failed", error, { event: "automation_listener_failed", event_type: eventType }));
    } catch (error) {
      eventLog.error("Event listener failed", error, { event: "automation_listener_failed", event_type: eventType });
    }
  }
  return event;
}

for (const definition of [
  { id: "twitch.follow", label: "Twitch follow", description: "A viewer follows a configured Twitch channel.", platform: "twitch" },
  { id: "twitch.raid", label: "Twitch raid received", description: "A configured Twitch channel receives a raid that appears in chat.", platform: "twitch" },
  { id: "twitch.subscribe", label: "Twitch subscription", description: "A configured Twitch channel receives a new subscription.", platform: "twitch", supportsTier: true },
  { id: "twitch.subscription_gift", label: "Twitch gifted subscriptions", description: "A viewer gifts one or more subscriptions in a configured Twitch channel.", platform: "twitch", supportsTier: true },
  { id: "discord.member_join", label: "Discord member joined", description: "A member joins the configured Discord server.", platform: "discord" }
]) registerEventType(definition);

module.exports = { emitLumiEvent, listEventTypes, onLumiEvent, registerEventType };
