// ─── Shared interfaces and utilities for all engine modules ──────────────────

export interface Citation {
  title: string;
  url: string;
  snippet: string;
  domain: string;
}

export interface EngineResponse {
  engineInternalName: "ChatGPT" | "Perplexity" | "Claude" | "Gemini" | "Brave";
  engineNumber: 1 | 2 | 3 | 4 | 5;
  engineDisplayName: string;
  engineSubtitle: string;
  success: boolean;
  responseText: string | null;
  citations: Citation[];
  errorMessage: string | null;
  durationMs: number;
}

export interface EngineError {
  code: "auth_error" | "rate_limit" | "timeout" | "network" | "parse_error" | "unknown";
  message: string;
  retryable: boolean;
}

export interface EngineConfig {
  timeoutMs: number;
  maxRetries: number;
}

export const DEFAULT_ENGINE_CONFIG: EngineConfig = {
  timeoutMs: 30_000,
  maxRetries: 1,
};

// ─── Utilities ────────────────────────────────────────────────────────────────

export function extractDomain(url: string): string {
  try {
    const u = new URL(url);
    return u.hostname.replace(/^www\./, "");
  } catch {
    return url;
  }
}

export function normalizeUrl(url: string): string {
  try {
    const u = new URL(url);
    return u.origin + u.pathname;
  } catch {
    return url;
  }
}

export function parseJsonSafely<T>(text: string): T | null {
  try {
    return JSON.parse(text) as T;
  } catch {
    return null;
  }
}

export function classifyError(status: number, message: string): EngineError {
  if (status === 401 || status === 403) {
    return { code: "auth_error", message, retryable: false };
  }
  if (status === 429) {
    return { code: "rate_limit", message, retryable: false };
  }
  if (status >= 500) {
    return { code: "network", message, retryable: true };
  }
  return { code: "unknown", message, retryable: false };
}

export async function retryWithBackoff<T>(
  fn: () => Promise<T>,
  maxRetries: number,
  isRetryable: (err: unknown) => boolean,
): Promise<T> {
  let lastErr: unknown;
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (err) {
      lastErr = err;
      if (attempt < maxRetries && isRetryable(err)) {
        await new Promise((res) => setTimeout(res, 1000 * (attempt + 1)));
        continue;
      }
      break;
    }
  }
  throw lastErr;
}

export async function fetchWithTimeout(
  url: string,
  init: RequestInit,
  timeoutMs: number,
): Promise<Response> {
  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeoutMs);
  try {
    return await fetch(url, { ...init, signal: controller.signal });
  } finally {
    clearTimeout(timer);
  }
}

// Engine display metadata (customer-facing — NO vendor names)
export const ENGINE_DISPLAY_META: Record<
  EngineResponse["engineInternalName"],
  { displayName: string; subtitle: string; number: EngineResponse["engineNumber"] }
> = {
  ChatGPT:    { displayName: "meSEO AI Engine 1", subtitle: "Conversational Search",        number: 1 },
  Perplexity: { displayName: "meSEO AI Engine 2", subtitle: "Citation-Focused Search",       number: 2 },
  Claude:     { displayName: "meSEO AI Engine 3", subtitle: "Reasoning-Focused Search",      number: 3 },
  Gemini:     { displayName: "meSEO AI Engine 4", subtitle: "Search-Grounded Generative",    number: 4 },
  Brave:      { displayName: "meSEO AI Engine 5", subtitle: "Independent Index Search",      number: 5 },
};
