/**
 * Pure helpers for the relay reconnect policy.
 *
 * Extracted from `RelayClient` so the decision rules — when to schedule a
 * reconnect, when to refuse to connect — live in one legible place that
 * unit tests can reach without booting the WS layer.
 *
 * The rules:
 *
 *  - **Terminal sessions never reconnect.** When the relay has explicitly
 *    rejected us (today: kind:22242 AUTH OK=false) the session is dead
 *    until the user re-engages (community switch or explicit preconnect).
 *    This guards the reconnect-timer catch handler — and the retry wrappers
 *    in `publishEvent` / `sendRawWithReconnectRetry` — from racing the
 *    `disconnected` state back to `reconnecting`.
 *
 *  - **No-op when a reconnect is already scheduled or in progress.**
 *    A pending timer or a live `wsId` means we have nothing to do.
 *
 *  - **No reconnect needed when nothing wants the socket.** No live
 *    subscription, no `keepAliveRequested` from `preconnect()` → don't
 *    keep an idle socket.
 */
export type RelayReconnectInputs = {
  terminal: boolean;
  hasPendingReconnect: boolean;
  hasLiveSocket: boolean;
  keepAliveRequested: boolean;
  hasLiveSubscriptions: boolean;
};

export function shouldScheduleReconnect(inputs: RelayReconnectInputs): boolean {
  if (inputs.terminal) return false;
  if (inputs.hasPendingReconnect) return false;
  if (inputs.hasLiveSocket) return false;
  if (!inputs.keepAliveRequested && !inputs.hasLiveSubscriptions) return false;
  return true;
}

export function shouldWaitForScheduledReconnect(inputs: {
  hasPendingReconnect: boolean;
}): boolean {
  return inputs.hasPendingReconnect;
}

/** Whether `ensureConnected()` should refuse with a terminal error. */
export function shouldRefuseConnect(inputs: { terminal: boolean }): boolean {
  return inputs.terminal;
}

export function isWebSocketClose(
  message: unknown,
): message is { type: "Close"; data?: unknown } {
  return (
    typeof message === "object" &&
    message !== null &&
    "type" in message &&
    message.type === "Close"
  );
}

export function isServiceRestartClose(message: unknown): boolean {
  if (!isWebSocketClose(message)) return false;
  if (!("data" in message)) return false;
  const data = message.data;
  return (
    typeof data === "object" &&
    data !== null &&
    "code" in data &&
    data.code === 1012
  );
}

/** Whether a WS-layer message is the plugin's `Error` frame. */
export function isWebSocketError(message: unknown): boolean {
  return (
    typeof message === "object" &&
    message !== null &&
    "type" in message &&
    message.type === "Error"
  );
}
