/**
 * Typed timeout error for OpenChrome.
 * Replaces fragile string-based timeout detection across the codebase.
 */
export class OpenChromeTimeoutError extends Error {
  /** Whether the operation may have produced useful partial state (e.g., partial DOM load). */
  readonly recoverable: boolean;
  /** Original operation label for diagnostics. */
  readonly label: string;
  /** Timeout duration in milliseconds. */
  readonly timeoutMs: number;
  /** True when the error was caused by overall tool deadline exhaustion, not an individual operation timeout. */
  readonly deadline: boolean;

  constructor(label: string, timeoutMs: number, recoverable = false, deadline = false) {
    const msg = deadline
      ? `${label}: deadline exceeded (budget exhausted)`
      : `${label} timed out after ${timeoutMs}ms`;
    super(msg);
    Object.setPrototypeOf(this, new.target.prototype);
    this.name = 'OpenChromeTimeoutError';
    this.label = label;
    this.timeoutMs = timeoutMs;
    this.recoverable = recoverable;
    this.deadline = deadline;
  }
}

/**
 * Type guard for timeout errors. Checks for:
 * 1. OpenChromeTimeoutError instances (preferred)
 * 2. Legacy string-based patterns including Puppeteer's "Waiting failed: Xms exceeded"
 */
export function isTimeoutError(error: unknown): error is OpenChromeTimeoutError | Error {
  if (error instanceof OpenChromeTimeoutError) return true;
  if (error instanceof Error) {
    const msg = error.message.toLowerCase();
    return (
      msg.includes('timed out') ||
      /waiting failed:.*exceeded/i.test(error.message)
    );
  }
  return false;
}
