// Loop detectors — detects repetitive patterns in assistant output
// that indicate a model is stuck in a loop.

export interface LoopDetectionResult {
  isLoop: boolean;
  reason?: string;
  confidence: number; // 0-1
}

const REPEATED_PHRASE_MIN_COUNT = 4;
const REPEATED_TOOL_MIN_COUNT = 3;

export function detectContentRepeat(messages: string[]): LoopDetectionResult {
  if (messages.length < REPEATED_PHRASE_MIN_COUNT) {
    return { isLoop: false, confidence: 0 };
  }

  const recent = messages.slice(-REPEATED_PHRASE_MIN_COUNT);
  const unique = new Set(recent);

  if (unique.size === 1) {
    return {
      isLoop: true,
      reason: `Same content repeated ${REPEATED_PHRASE_MIN_COUNT} times`,
      confidence: 0.9,
    };
  }

  if (unique.size <= 2 && recent.length >= 4) {
    return {
      isLoop: true,
      reason: 'Content oscillating between two variants',
      confidence: 0.7,
    };
  }

  return { isLoop: false, confidence: 0 };
}

export function detectToolLoop(toolNames: string[]): LoopDetectionResult {
  if (toolNames.length < REPEATED_TOOL_MIN_COUNT) return { isLoop: false, confidence: 0 };

  const recent = toolNames.slice(-REPEATED_TOOL_MIN_COUNT);
  const unique = new Set(recent);

  if (unique.size === 1) {
    return {
      isLoop: true,
      reason: `Same tool "${recent[0]}" called ${REPEATED_TOOL_MIN_COUNT} times consecutively`,
      confidence: 0.85,
    };
  }

  return { isLoop: false, confidence: 0 };
}

export function detectDoomLoop(
  messages: string[],
  toolNames: string[],
): LoopDetectionResult {
  const contentResult = detectContentRepeat(messages);
  if (contentResult.isLoop) return contentResult;

  const toolResult = detectToolLoop(toolNames);
  if (toolResult.isLoop) return toolResult;

  return { isLoop: false, confidence: 0 };
}
