/**
 * Types for secret scanning functionality
 */

/**
 * A pattern used to detect secrets
 */
export interface SecretPattern {
  /** Name of the pattern (e.g., "AWS Access Key") */
  name: string;
  /** Regular expression to match the secret */
  pattern: RegExp;
  /** Description of what this pattern detects */
  description: string;
  /** Severity level of the secret if found */
  severity: "critical" | "high" | "medium" | "low";
}

/**
 * A matched secret in content
 */
export interface SecretMatch {
  /** The pattern that matched */
  patternName: string;
  /** The matched text (may be redacted in output) */
  match: string;
  /** Line number where the match was found (1-indexed) */
  line: number;
  /** Column number where the match starts (1-indexed) */
  column: number;
  /** Severity of this match */
  severity: "critical" | "high" | "medium" | "low";
  /** Additional context (line content with match highlighted) */
  context?: string;
}

/**
 * Result of scanning a file or content
 */
export interface SecretScanResult {
  /** Path to the file that was scanned (optional) */
  filePath?: string;
  /** Whether any secrets were found */
  hasSecrets: boolean;
  /** Array of matched secrets */
  matches: SecretMatch[];
  /** Number of secrets found */
  count: number;
  /** Whether the file was successfully scanned (false if errors occurred) */
  scannedSuccessfully: boolean;
  /** Error message if scan failed */
  scanError?: string;
}

/**
 * Configuration for secret scanner
 */
export interface SecretScannerConfig {
  /** Custom patterns to add to built-in patterns */
  customPatterns?: SecretPattern[];
  /** File paths to exclude from scanning (glob patterns) */
  excludePatterns?: string[];
  /** Whether to scan binary files */
  scanBinaryFiles?: boolean;
  /** Maximum file size to scan (in bytes) */
  maxFileSize?: number;
}

/**
 * Error thrown when secrets are detected during commit
 */
export class SecretsDetectedError extends Error {
  constructor(
    public readonly results: SecretScanResult[],
    message?: string
  ) {
    super(message ?? `Secrets detected in ${results.length.toString()} file(s). Commit blocked.`);
    this.name = "SecretsDetectedError";
  }

  /**
   * Get a formatted error message with details
   */
  getDetailedMessage(): string {
    const lines: string[] = [
      "❌ SECRETS DETECTED - COMMIT BLOCKED",
      "",
      "The following files contain potential secrets:",
      "",
    ];

    for (const result of this.results) {
      if (!result.hasSecrets) continue;

      lines.push(`📁 ${result.filePath ?? "(content)"}`);
      for (const match of result.matches) {
        lines.push(
          `   Line ${match.line.toString()}:${match.column.toString()} - ${match.patternName} [${match.severity.toUpperCase()}]`
        );
        if (match.context) {
          lines.push(`   ${match.context}`);
        }
      }
      lines.push("");
    }

    // Report files that could not be scanned
    const errorResults = this.results.filter((r) => !r.scannedSuccessfully);
    if (errorResults.length > 0) {
      lines.push("⚠️ The following files could not be scanned:");
      lines.push("");
      for (const result of errorResults) {
        lines.push(`📁 ${result.filePath ?? "(content)"}`);
        if (result.scanError) {
          lines.push(`   Error: ${result.scanError}`);
        }
      }
      lines.push("");
    }

    lines.push("Please remove these secrets before committing.");
    lines.push("Consider using environment variables or a secrets management system.");

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