export function createNotificationCoreClient({ baseUrl, token }) {
  const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
  const internalToken = typeof token === "string" ? token.trim() : "";

  return {
    isConfigured() {
      return Boolean(normalizedBaseUrl && internalToken);
    },

    async createEvent(command) {
      return requestJson({
        baseUrl: normalizedBaseUrl,
        token: internalToken,
        method: "POST",
        pathname: "/internal/notifications/events",
        body: command,
      });
    },

    async listNotifications({ subject, surface, limit, unreadOnly }) {
      const searchParams = new URLSearchParams();
      searchParams.set("surface", surface || "hub");
      if (limit) searchParams.set("limit", String(limit));
      if (unreadOnly) searchParams.set("unreadOnly", "1");
      return requestJson({
        baseUrl: normalizedBaseUrl,
        token: internalToken,
        method: "GET",
        pathname: `/api/notifications?${searchParams.toString()}`,
        subject,
      });
    },

    async markNotificationRead({ subject, deliveryId }) {
      return requestJson({
        baseUrl: normalizedBaseUrl,
        token: internalToken,
        method: "POST",
        pathname: `/api/notifications/${encodeURIComponent(deliveryId)}/read`,
        subject,
      });
    },

    async markAllNotificationsRead({ subject, surface }) {
      const searchParams = new URLSearchParams();
      searchParams.set("surface", surface || "hub");
      return requestJson({
        baseUrl: normalizedBaseUrl,
        token: internalToken,
        method: "POST",
        pathname: `/api/notifications/read-all?${searchParams.toString()}`,
        subject,
      });
    },

    async openNotificationStream({ subject, surface, signal }) {
      if (!normalizedBaseUrl || !internalToken) {
        throw new Error("notification_core_not_configured");
      }

      const searchParams = new URLSearchParams();
      searchParams.set("surface", surface || "hub");
      const response = await fetch(`${normalizedBaseUrl}/api/notifications/stream?${searchParams.toString()}`, {
        method: "GET",
        headers: buildHeaders(internalToken, subject),
        signal,
      });

      if (!response.ok || !response.body) {
        throw new Error(await readError(response));
      }

      return response;
    },
  };
}

async function requestJson({ baseUrl, token, method, pathname, body, subject }) {
  if (!baseUrl || !token) {
    throw new Error("notification_core_not_configured");
  }

  const response = await fetch(`${baseUrl}${pathname}`, {
    method,
    headers: buildHeaders(token, subject, body !== undefined),
    body: body === undefined ? undefined : JSON.stringify(body),
  });

  let parsed = null;
  try {
    parsed = await response.json();
  } catch {}

  if (!response.ok) {
    const error = new Error(parsed?.error ? String(parsed.error) : `notification_core_http_${response.status}`);
    error.status = response.status;
    error.payload = parsed;
    throw error;
  }

  return parsed;
}

function buildHeaders(token, subject, hasJsonBody = false) {
  const headers = {
    Accept: "application/json",
    Authorization: `Bearer ${token}`,
  };
  if (hasJsonBody) headers["Content-Type"] = "application/json";
  if (subject?.userId) headers["X-NODEDC-User-Id"] = subject.userId;
  if (subject?.email) headers["X-NODEDC-User-Email"] = subject.email;
  return headers;
}

async function readError(response) {
  try {
    const parsed = await response.json();
    if (parsed?.error) return String(parsed.error);
  } catch {}
  return `notification_core_http_${response.status}`;
}

function normalizeBaseUrl(value) {
  return typeof value === "string" && value.trim() ? value.trim().replace(/\/+$/, "") : "";
}
