/**
 * Language detection for code blocks using simple heuristics (no heavy ML).
 * Returns a language label for display badges.
 */

export interface LanguageMatch {
  /** Detected language label (e.g. "TypeScript", "Rust") */
  label: string;
  /** Short label for badges (e.g. "TS", "Rust") */
  short: string;
  /** Confidence: 0-1 */
  confidence: number;
}

/** Map language aliases to canonical labels */
const LANG_ALIASES: Record<string, { label: string; short: string }> = {
  ts: { label: 'TypeScript', short: 'TS' },
  tsx: { label: 'TypeScript (React)', short: 'TSX' },
  js: { label: 'JavaScript', short: 'JS' },
  jsx: { label: 'JavaScript (React)', short: 'JSX' },
  rs: { label: 'Rust', short: 'Rust' },
  py: { label: 'Python', short: 'Py' },
  go: { label: 'Go', short: 'Go' },
  rb: { label: 'Ruby', short: 'RB' },
  java: { label: 'Java', short: 'Java' },
  kt: { label: 'Kotlin', short: 'Kt' },
  swift: { label: 'Swift', short: 'Swift' },
  cs: { label: 'C#', short: 'C#' },
  cpp: { label: 'C++', short: 'C++' },
  c: { label: 'C', short: 'C' },
  h: { label: 'C/C++ Header', short: 'H' },
  hpp: { label: 'C++ Header', short: 'HPP' },
  css: { label: 'CSS', short: 'CSS' },
  scss: { label: 'SCSS', short: 'SCSS' },
  html: { label: 'HTML', short: 'HTML' },
  xml: { label: 'XML', short: 'XML' },
  json: { label: 'JSON', short: 'JSON' },
  yaml: { label: 'YAML', short: 'YAML' },
  yml: { label: 'YAML', short: 'YAML' },
  md: { label: 'Markdown', short: 'MD' },
  sh: { label: 'Shell', short: 'SH' },
  bash: { label: 'Bash', short: 'Bash' },
  zsh: { label: 'Zsh', short: 'Zsh' },
  sql: { label: 'SQL', short: 'SQL' },
  graphql: { label: 'GraphQL', short: 'GQL' },
  dockerfile: { label: 'Dockerfile', short: 'Docker' },
  tf: { label: 'Terraform', short: 'TF' },
  toml: { label: 'TOML', short: 'TOML' },
  ini: { label: 'INI', short: 'INI' },
  env: { label: 'Env', short: 'ENV' },
  proto: { label: 'Protocol Buffer', short: 'Proto' },
};

/** Language detection rules: pattern → language key */
const DETECTION_RULES: Array<{ pattern: RegExp; lang: string; confidence: number }> = [
  // Rust
  { pattern: /\bfn\s+\w+\s*[\({]/, lang: 'rs', confidence: 0.9 },
  { pattern: /\blet\s+(mut\s+)?\w+\s*:/, lang: 'rs', confidence: 0.7 },
  { pattern: /\bimpl\s+\w+/, lang: 'rs', confidence: 0.8 },
  { pattern: /\buse\s+\w+::/, lang: 'rs', confidence: 0.7 },
  { pattern: /\bmatch\s+\w+\s*\{/, lang: 'rs', confidence: 0.8 },
  { pattern: /\b->\s*\w+/, lang: 'rs', confidence: 0.6 },

  // TypeScript / JavaScript
  { pattern: /\bimport\s+.*\s+from\s+['"]/, lang: 'ts', confidence: 0.9 },
  { pattern: /\bexport\s+(default\s+)?(function|const|class|type|interface)/, lang: 'ts', confidence: 0.9 },
  { pattern: /\bconst\s+\w+:\s*\w+\s*=/, lang: 'ts', confidence: 0.8 },
  { pattern: /\blet\s+\w+:\s*\w+\s*=/, lang: 'ts', confidence: 0.8 },
  { pattern: /interface\s+\w+\s*\{/, lang: 'ts', confidence: 0.9 },
  { pattern: /\btype\s+\w+\s*=/, lang: 'ts', confidence: 0.8 },
  { pattern: /=>\s*[{(]?\s*\w+:/, lang: 'ts', confidence: 0.7 },
  { pattern: /<\w+[^>]*>.*<\/\w+>/s, lang: 'tsx', confidence: 0.7 },

  // Python
  { pattern: /\bdef\s+\w+\s*\([^)]*\)\s*(->\s*\w+)?:/, lang: 'py', confidence: 0.95 },
  { pattern: /\bclass\s+\w+.*:/, lang: 'py', confidence: 0.8 },
  { pattern: /\bimport\s+\w+\s*,?\s*(from\s+\w+\s*)?/i, lang: 'py', confidence: 0.6 },
  { pattern: /\bprint\s*\(/, lang: 'py', confidence: 0.5 },
  { pattern: /\bself\./, lang: 'py', confidence: 0.8 },
  { pattern: /@\w+\s*\n/, lang: 'py', confidence: 0.6 },

  // Go
  { pattern: /\bpackage\s+\w+/, lang: 'go', confidence: 0.95 },
  { pattern: /\bfunc\s+\w+\s*\(/, lang: 'go', confidence: 0.9 },
  { pattern: /\bfunc\s*\(/, lang: 'go', confidence: 0.8 },
  { pattern: /:=\s*/, lang: 'go', confidence: 0.7 },
  { pattern: /\bgo\s+func/, lang: 'go', confidence: 0.9 },
  { pattern: /\bchan\s+\w+/, lang: 'go', confidence: 0.8 },

  // Java
  { pattern: /\bpublic\s+(class|interface|enum)\s+\w+/, lang: 'java', confidence: 0.95 },
  { pattern: /\bSystem\.out\.print/, lang: 'java', confidence: 0.9 },

  // CSS
  { pattern: /\b[a-z-]+\s*:\s*[^;{}\n]+;/, lang: 'css', confidence: 0.7 },
  { pattern: /\.[a-z][\w-]*\s*\{/, lang: 'css', confidence: 0.8 },
  { pattern: /@media\s*\(/, lang: 'css', confidence: 0.9 },
  { pattern: /@import\s+/, lang: 'css', confidence: 0.8 },

  // HTML
  { pattern: /<html[\s>]/i, lang: 'html', confidence: 0.9 },
  { pattern: /<div[\s>]/i, lang: 'html', confidence: 0.7 },
  { pattern: /<\/\w+>/, lang: 'html', confidence: 0.5 },

  // SQL
  { pattern: /\bSELECT\s+.+\s+FROM\b/i, lang: 'sql', confidence: 0.95 },
  { pattern: /\bINSERT\s+INTO\b/i, lang: 'sql', confidence: 0.95 },
  { pattern: /\bCREATE\s+TABLE\b/i, lang: 'sql', confidence: 0.95 },

  // Shell
  { pattern: /^#!/m, lang: 'sh', confidence: 0.95 },
  { pattern: /\becho\s+/, lang: 'sh', confidence: 0.6 },
  { pattern: /\bexport\s+\w+=/, lang: 'sh', confidence: 0.6 },

  // JSON
  { pattern: /^\s*\{[\s\S]*"[\w-]+":\s*/, lang: 'json', confidence: 0.8 },
  { pattern: /^\s*\[[\s\S]*\{/, lang: 'json', confidence: 0.7 },

  // YAML
  { pattern: /^\s*[\w-]+:\s*$/m, lang: 'yaml', confidence: 0.6 },
];

/** Normalize a language label/alias to a canonical label+short */
function normalize(lang: string): { label: string; short: string } {
  const lower = lang.toLowerCase().trim();
  if (LANG_ALIASES[lower]) return LANG_ALIASES[lower];
  // Capitalize first letter for unknown
  return { label: lang.charAt(0).toUpperCase() + lang.slice(1), short: lang.slice(0, 4) };
}

/**
 * Detect the programming language of a code snippet.
 * Returns the best match or null if no patterns match.
 */
export function detectLanguage(code: string): LanguageMatch | null {
  let best: { lang: string; confidence: number } | null = null;

  for (const rule of DETECTION_RULES) {
    if (rule.pattern.test(code)) {
      if (!best || rule.confidence > best.confidence) {
        best = { lang: rule.lang, confidence: rule.confidence };
      }
    }
  }

  if (!best) return null;
  return { ...normalize(best.lang), confidence: best.confidence };
}

/**
 * Get a language label from a fenced code block language tag.
 * Handles aliases and returns canonical label+short.
 */
export function getLanguageFromTag(tag: string | undefined): LanguageMatch | null {
  if (!tag) return null;
  const lower = tag.toLowerCase().trim();
  if (LANG_ALIASES[lower]) {
    return { ...LANG_ALIASES[lower], confidence: 1 };
  }
  return { label: tag, short: tag.slice(0, 4), confidence: 1 };
}

/** Extract the language tag from a fenced code block marker (e.g. "```ts" → "ts") */
export function extractLanguageFromFence(fence: string): string | undefined {
  const match = fence.match(/^```(\w*)/);
  return match?.[1] || undefined;
}
