/**
 * Content Validation Utilities
 *
 * Validates that content is suitable for RAG knowledge base:
 * - Accepts: Plain text, Markdown
 * - Rejects: JSON, XML, JavaScript, HTML, SQL, and other code/structured formats
 */

/**
 * Content validation result
 */
export interface ValidationResult {
  isValid: boolean;
  reason?: string;
  detectedFormat?: string;
}

/**
 * Detect if content contains structured data or code
 *
 * @param content - Text content to validate
 * @returns Validation result with reason if invalid
 */
export function validateContent(content: string): ValidationResult {
  const trimmedContent = content.trim();

  if (trimmedContent.length === 0) {
    return {
      isValid: false,
      reason: 'Content is empty',
    };
  }

  // Check for JSON
  if (looksLikeJSON(trimmedContent)) {
    return {
      isValid: false,
      reason: 'Content appears to be JSON data. Only plain text and Markdown are allowed.',
      detectedFormat: 'JSON',
    };
  }

  // Check for XML/HTML
  if (looksLikeXML(trimmedContent)) {
    return {
      isValid: false,
      reason: 'Content appears to be XML/HTML. Only plain text and Markdown are allowed.',
      detectedFormat: 'XML/HTML',
    };
  }

  // Check for JavaScript/TypeScript code
  if (looksLikeJavaScript(trimmedContent)) {
    return {
      isValid: false,
      reason: 'Content appears to be JavaScript/TypeScript code. Only plain text and Markdown are allowed.',
      detectedFormat: 'JavaScript/TypeScript',
    };
  }

  // Check for Python code
  if (looksLikePython(trimmedContent)) {
    return {
      isValid: false,
      reason: 'Content appears to be Python code. Only plain text and Markdown are allowed.',
      detectedFormat: 'Python',
    };
  }

  // Check for SQL
  if (looksLikeSQL(trimmedContent)) {
    return {
      isValid: false,
      reason: 'Content appears to be SQL code. Only plain text and Markdown are allowed.',
      detectedFormat: 'SQL',
    };
  }

  // Check for YAML
  if (looksLikeYAML(trimmedContent)) {
    return {
      isValid: false,
      reason: 'Content appears to be YAML data. Only plain text and Markdown are allowed.',
      detectedFormat: 'YAML',
    };
  }

  // Check for CSV (with high confidence threshold)
  if (looksLikeCSV(trimmedContent)) {
    return {
      isValid: false,
      reason: 'Content appears to be CSV data. Only plain text and Markdown are allowed.',
      detectedFormat: 'CSV',
    };
  }

  // Check for excessive code-like patterns
  if (hasExcessiveCodePatterns(trimmedContent)) {
    return {
      isValid: false,
      reason: 'Content contains too many code-like patterns. Only plain text and Markdown are allowed.',
      detectedFormat: 'Code',
    };
  }

  // Content passes all checks
  return {
    isValid: true,
  };
}

/**
 * Check if content looks like JSON
 */
function looksLikeJSON(content: string): boolean {
  // Try to parse as JSON
  if (content.startsWith('{') || content.startsWith('[')) {
    try {
      JSON.parse(content);
      return true;
    } catch {
      // Not valid JSON, but might still look like it
    }
  }

  // Check for JSON-like patterns (high confidence)
  const jsonPatterns = [
    /^\s*\{[\s\S]*\}\s*$/,  // Object literal
    /^\s*\[[\s\S]*\]\s*$/,  // Array literal
    /"[^"]+"\s*:\s*[{\["]/g,  // Key-value pairs
  ];

  const jsonKeywords = ['"type":', '"id":', '"data":', '"properties":'];

  const hasJSONStructure = jsonPatterns.some(pattern => pattern.test(content));
  const hasMultipleJSONKeywords = jsonKeywords.filter(keyword => content.includes(keyword)).length >= 2;

  return hasJSONStructure && hasMultipleJSONKeywords;
}

/**
 * Check if content looks like XML or HTML
 */
function looksLikeXML(content: string): boolean {
  // Check for XML/HTML tags
  const xmlPattern = /<[a-zA-Z][^>]*>[\s\S]*<\/[a-zA-Z][^>]*>/;
  const hasXMLTags = xmlPattern.test(content);

  // Count opening and closing tags
  const openTags = (content.match(/<[a-zA-Z][^>]*>/g) || []).length;
  const closeTags = (content.match(/<\/[a-zA-Z][^>]*>/g) || []).length;

  // If more than 3 matching tags, likely XML/HTML
  const tagCount = Math.min(openTags, closeTags);

  // Check for XML declaration
  const hasXMLDeclaration = content.includes('<?xml');

  return hasXMLTags && (tagCount >= 3 || hasXMLDeclaration);
}

/**
 * Check if content looks like JavaScript/TypeScript
 */
function looksLikeJavaScript(content: string): boolean {
  const jsPatterns = [
    /\bfunction\s+\w+\s*\(/,
    /\bconst\s+\w+\s*=/,
    /\blet\s+\w+\s*=/,
    /\bvar\s+\w+\s*=/,
    /\bclass\s+\w+/,
    /\bimport\s+.*\bfrom\b/,
    /\bexport\s+(default\s+)?(function|class|const)/,
    /=>\s*\{/,  // Arrow functions
    /\basync\s+function/,
    /\bawait\s+\w+/,
  ];

  const matchCount = jsPatterns.filter(pattern => pattern.test(content)).length;

  // If 3 or more JS patterns match, likely JavaScript
  return matchCount >= 3;
}

/**
 * Check if content looks like Python
 */
function looksLikePython(content: string): boolean {
  const pythonPatterns = [
    /\bdef\s+\w+\s*\(/,
    /\bclass\s+\w+:/,
    /\bimport\s+\w+/,
    /\bfrom\s+\w+\s+import\b/,
    /\bif\s+__name__\s*==\s*['"']__main__['"']/,
    /\bself\.\w+/,
    /:\s*$\n\s{4,}/m,  // Indentation after colon
  ];

  const matchCount = pythonPatterns.filter(pattern => pattern.test(content)).length;

  return matchCount >= 3;
}

/**
 * Check if content looks like SQL
 */
function looksLikeSQL(content: string): boolean {
  const sqlKeywords = [
    /\bSELECT\s+.*\s+FROM\b/i,
    /\bINSERT\s+INTO\b/i,
    /\bUPDATE\s+.*\s+SET\b/i,
    /\bDELETE\s+FROM\b/i,
    /\bCREATE\s+(TABLE|VIEW|INDEX)\b/i,
    /\bALTER\s+TABLE\b/i,
    /\bDROP\s+(TABLE|VIEW|INDEX)\b/i,
    /\bJOIN\b.*\bON\b/i,
  ];

  const matchCount = sqlKeywords.filter(pattern => pattern.test(content)).length;

  return matchCount >= 2;
}

/**
 * Check if content looks like YAML
 */
function looksLikeYAML(content: string): boolean {
  const yamlPatterns = [
    /^[a-zA-Z_][\w-]*:\s*.+$/m,  // Key-value pairs
    /^\s*-\s+[a-zA-Z_][\w-]*:/m,  // List items with keys
    /^---\s*$/m,  // Document separator
  ];

  // Count lines that look like YAML
  const lines = content.split('\n');
  const yamlLikeLines = lines.filter(line =>
    /^[a-zA-Z_][\w-]*:\s*.+$/.test(line.trim()) ||
    /^\s*-\s+/.test(line)
  ).length;

  const hasYAMLSeparator = content.includes('---');
  const yamlLineRatio = yamlLikeLines / lines.length;

  // If more than 40% of lines look like YAML, it's probably YAML
  return (yamlLineRatio > 0.4 && yamlLikeLines >= 5) || hasYAMLSeparator;
}

/**
 * Check if content looks like CSV
 */
function looksLikeCSV(content: string): boolean {
  const lines = content.trim().split('\n');

  if (lines.length < 3) {
    return false;  // Need at least a few lines to be CSV
  }

  // Count commas in each line
  const commaCounts = lines.slice(0, 10).map(line =>
    (line.match(/,/g) || []).length
  );

  // Check if most lines have similar comma counts
  if (commaCounts.length === 0) return false;

  const avgCommas = commaCounts.reduce((a, b) => a + b, 0) / commaCounts.length;
  const hasConsistentCommas = commaCounts.filter(count =>
    Math.abs(count - avgCommas) <= 1
  ).length >= commaCounts.length * 0.8;

  // Need at least 3 commas per line on average and consistency
  return avgCommas >= 3 && hasConsistentCommas;
}

/**
 * Check for excessive code-like patterns
 */
function hasExcessiveCodePatterns(content: string): boolean {
  const codePatterns = [
    /[{}\[\]();]/g,  // Brackets and braces
    /[=<>!]+/g,  // Operators
    /\b0x[0-9a-fA-F]+\b/g,  // Hex numbers
    /\/\/.*/g,  // Single-line comments
    /\/\*[\s\S]*?\*\//g,  // Multi-line comments
  ];

  let totalMatches = 0;
  for (const pattern of codePatterns) {
    const matches = content.match(pattern) || [];
    totalMatches += matches.length;
  }

  // If there are excessive code patterns relative to content length
  const codePatternDensity = totalMatches / content.length;

  // More than 10% of characters are code-like
  return codePatternDensity > 0.1 && totalMatches > 50;
}

/**
 * Check if PDF text extraction contains mostly structured content
 *
 * This is useful for validating PDFs after extraction
 */
export function validatePDFText(extractedText: string): ValidationResult {
  // PDFs might contain some special characters from extraction
  // Be more lenient with PDF content but still reject obvious code/data

  const result = validateContent(extractedText);

  // If it failed basic validation, check if it's a false positive
  if (!result.isValid) {
    // Check if it's mostly readable text despite some code-like elements
    const readableTextRatio = calculateReadableTextRatio(extractedText);

    // If more than 70% is readable text, allow it
    if (readableTextRatio > 0.7) {
      return {
        isValid: true,
      };
    }
  }

  return result;
}

/**
 * Calculate ratio of readable text to total content
 */
function calculateReadableTextRatio(content: string): number {
  // Remove code-like patterns
  let cleanedContent = content
    .replace(/[{}\[\]();]/g, '')  // Remove brackets
    .replace(/[=<>!]+/g, '')  // Remove operators
    .replace(/\b0x[0-9a-fA-F]+\b/g, '')  // Remove hex
    .replace(/\/\/.*/g, '')  // Remove comments
    .replace(/\/\*[\s\S]*?\*\//g, '');  // Remove multi-line comments

  // Count words (sequences of letters)
  const words = cleanedContent.match(/[a-zA-Z]{3,}/g) || [];
  const wordCount = words.length;

  // Count total characters
  const totalChars = content.length;

  // Readable text should have reasonable word density
  const avgWordLength = 5;
  const estimatedReadableChars = wordCount * avgWordLength;

  return Math.min(estimatedReadableChars / totalChars, 1.0);
}
