export interface HttpFailureContext {
  role?: string;
  url: string;
  status: number;
  location?: string | null;
  html?: string;
  extra?: string;
  serverLogs?: string;
}

export class HttpDiagnostics {
  static clipString(str: string, max = 1200): string {
    if (str.length <= max) return str;
    return str.substring(0, max) + `... [clipped ${str.length - max} chars]`;
  }

  static formatHttpFailure({ role, url, status, location, html, extra, serverLogs }: HttpFailureContext): string {
    const lines = [
      `HTTP Failure: ${status} for ${url}`,
      role ? `Role: ${role}` : null,
      location ? `Location: ${location}` : null,
      extra ? `Extra: ${extra}` : null,
      html ? `HTML Body (clipped):\n${this.clipString(html)}` : 'No HTML body provided',
      serverLogs ? `\n--- Server Log Tail ---\n${serverLogs}` : null,
    ].filter(Boolean);

    return lines.join('\n');
  }

  static assertHtmlContains(html: string, mustContain: string | string[], context: HttpFailureContext): void {
    const targets = Array.isArray(mustContain) ? mustContain : [mustContain];
    for (const target of targets) {
      if (!html.includes(target)) {
        const message = this.formatHttpFailure({
          ...context,
          extra: `Expected HTML to contain: "${target}"`,
          html,
        });
        throw new Error(message);
      }
    }
  }

  static assertHtmlNotContains(html: string, mustNotContain: string | string[], context: HttpFailureContext): void {
    const targets = Array.isArray(mustNotContain) ? mustNotContain : [mustNotContain];
    for (const target of targets) {
      if (html.includes(target)) {
        const message = this.formatHttpFailure({
          ...context,
          extra: `Expected HTML NOT to contain: "${target}"`,
          html,
        });
        throw new Error(message);
      }
    }
  }
}
