import type { GatewayStatus } from '@/types/gateway';

export const CHAT_HISTORY_RPC_TIMEOUT_MS = 35_000;
export const CHAT_HISTORY_STARTUP_RETRY_DELAYS_MS = [800, 2_000, 4_000, 8_000] as const;
export const CHAT_HISTORY_STARTUP_CONNECTION_GRACE_MS = 30_000;
export const CHAT_HISTORY_STARTUP_RUNNING_WINDOW_MS =
  CHAT_HISTORY_RPC_TIMEOUT_MS + CHAT_HISTORY_STARTUP_CONNECTION_GRACE_MS;
export const CHAT_HISTORY_DISK_FALLBACK_TIMEOUT_MS = 4_000;
export const CHAT_HISTORY_DEFAULT_LOADING_SAFETY_TIMEOUT_MS = 15_000;
export const CHAT_HISTORY_LOADING_SAFETY_TIMEOUT_MS =
  CHAT_HISTORY_RPC_TIMEOUT_MS * (CHAT_HISTORY_STARTUP_RETRY_DELAYS_MS.length + 1)
  + CHAT_HISTORY_STARTUP_RETRY_DELAYS_MS.reduce((sum, delay) => sum + delay, 0)
  + 2_000;

export type HistoryRetryErrorKind = 'timeout' | 'gateway_unavailable' | 'gateway_startup';

export function classifyHistoryStartupRetryError(error: unknown): HistoryRetryErrorKind | null {
  const message = String(error).toLowerCase();

  if (
    message.includes('unavailable during gateway startup')
    || message.includes('unavailable during startup')
    || message.includes('not yet ready')
    || message.includes('service not initialized')
  ) {
    return 'gateway_startup';
  }

  if (
    message.includes('rpc timeout: chat.history')
    || message.includes('gateway rpc timeout: chat.history')
    || message.includes('gateway ws timeout: chat.history')
    || message.includes('request timed out')
  ) {
    return 'timeout';
  }

  if (
    message.includes('gateway not connected')
    || message.includes('gateway socket is not connected')
    || message.includes('gateway is unavailable')
    || message.includes('service channel unavailable')
    || message.includes('websocket closed before handshake')
    || message.includes('connect handshake timeout')
    || message.includes('gateway ws connect timeout')
    || message.includes('gateway connection closed')
  ) {
    return 'gateway_unavailable';
  }

  return null;
}

export function shouldRetryStartupHistoryLoad(
  gatewayStatus: GatewayStatus | undefined,
  errorKind: HistoryRetryErrorKind | null,
): boolean {
  if (!gatewayStatus || !errorKind) return false;

  // The gateway explicitly told us it's still initializing -- always retry
  if (errorKind === 'gateway_startup') {
    return true;
  }

  if (gatewayStatus.state === 'starting') {
    return true;
  }

  if (gatewayStatus.state !== 'running') {
    return false;
  }

  if (gatewayStatus.connectedAt == null) {
    return true;
  }

  return Date.now() - gatewayStatus.connectedAt <= CHAT_HISTORY_STARTUP_RUNNING_WINDOW_MS;
}

export async function sleep(ms: number): Promise<void> {
  await new Promise((resolve) => setTimeout(resolve, ms));
}

export function getStartupHistoryTimeoutOverride(
  isInitialForegroundLoad: boolean,
): number | undefined {
  return isInitialForegroundLoad ? CHAT_HISTORY_RPC_TIMEOUT_MS : undefined;
}

export function getHistoryLoadingSafetyTimeout(isInitialForegroundLoad: boolean): number {
  return isInitialForegroundLoad
    ? CHAT_HISTORY_LOADING_SAFETY_TIMEOUT_MS
    : CHAT_HISTORY_DEFAULT_LOADING_SAFETY_TIMEOUT_MS;
}
