export interface ReputationResult {
  source: string;
  score: number;
  isSpam: boolean;
  confidence: number;
  category: string;
  cachedAt?: Date;
}

const cache = new Map<string, { result: ReputationResult; expiresAt: number }>();
const CACHE_TTL_MS = 24 * 60 * 60 * 1000;

interface CircuitBreakerState {
  failures: number;
  lastFailure: number;
  isOpen: boolean;
}

const circuitBreakers = new Map<string, CircuitBreakerState>();
const MAX_FAILURES = 3;
const RESET_TIMEOUT_MS = 60_000;

function isCircuitOpen(source: string): boolean {
  const state = circuitBreakers.get(source);
  if (!state) return false;
  if (!state.isOpen) return false;
  if (Date.now() - state.lastFailure > RESET_TIMEOUT_MS) {
    state.isOpen = false;
    state.failures = 0;
    return false;
  }
  return true;
}

function recordFailure(source: string): void {
  const state = circuitBreakers.get(source) ?? { failures: 0, lastFailure: 0, isOpen: false };
  state.failures++;
  state.lastFailure = Date.now();
  if (state.failures >= MAX_FAILURES) {
    state.isOpen = true;
  }
  circuitBreakers.set(source, state);
}

export async function lookupHiya(phoneNumber: string): Promise<ReputationResult | null> {
  if (isCircuitOpen("hiya")) return null;
  try {
    return {
      source: "hiya",
      score: 0,
      isSpam: false,
      confidence: 0,
      category: "unknown",
    };
  } catch {
    recordFailure("hiya");
    return null;
  }
}

export async function lookupTruecaller(phoneNumber: string): Promise<ReputationResult | null> {
  if (isCircuitOpen("truecaller")) return null;
  try {
    return {
      source: "truecaller",
      score: 0,
      isSpam: false,
      confidence: 0,
      category: "unknown",
    };
  } catch {
    recordFailure("truecaller");
    return null;
  }
}

export async function lookupInternalDB(phoneNumber: string): Promise<ReputationResult | null> {
  const cached = cache.get(phoneNumber);
  if (cached && Date.now() < cached.expiresAt) {
    return cached.result;
  }
  return null;
}

export async function cacheReputation(
  phoneNumber: string,
  result: ReputationResult,
): Promise<void> {
  cache.set(phoneNumber, {
    result,
    expiresAt: Date.now() + CACHE_TTL_MS,
  });
}

export async function checkReputation(phoneNumber: string): Promise<{
  source: string;
  score: number;
  isSpam: boolean;
  confidence: number;
  category: string;
} | null> {
  const cached = await lookupInternalDB(phoneNumber);
  if (cached) return cached;

  const hiya = await lookupHiya(phoneNumber);
  if (hiya && hiya.confidence > 0.5) {
    await cacheReputation(phoneNumber, hiya);
    return hiya;
  }

  const truecaller = await lookupTruecaller(phoneNumber);
  if (truecaller && truecaller.confidence > 0.5) {
    await cacheReputation(phoneNumber, truecaller);
    return truecaller;
  }

  return null;
}
