/**
 * Content Scorer — Client-side SEO + LLMO + Humanization scoring.
 * Runs in the browser with 300ms debounce. No API calls.
 */

export interface ScoreFactor { name: string; score: number; max: number; status: "pass" | "partial" | "fail"; tip: string | null }
export interface ContentScores {
  seo: { score: number; max: number; factors: ScoreFactor[] };
  llmo: { score: number; max: number; factors: ScoreFactor[] };
  human: { score: number; max: number; factors: ScoreFactor[] };
  grade: string;
  wordCount: number;
  readingTime: number;
  charCount: number;
  paragraphCount: number;
}

function words(text: string): string[] { return text.split(/\s+/).filter(Boolean); }
function countOccurrences(text: string, kw: string): number {
  if (!kw) return 0;
  const re = new RegExp(kw.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi");
  return (text.match(re) || []).length;
}

function factor(name: string, earned: number, max: number, tip: string | null): ScoreFactor {
  return { name, score: earned, max, status: earned >= max ? "pass" : earned > 0 ? "partial" : "fail", tip: earned >= max ? null : tip };
}

// Flesch-Kincaid grade level approximation
function readabilityGrade(text: string): number {
  const w = words(text);
  const sentences = text.split(/[.!?]+/).filter((s) => s.trim().length > 5);
  const syllables = w.reduce((n, word) => n + Math.max(1, word.replace(/[^aeiouy]/gi, "").length), 0);
  if (w.length === 0 || sentences.length === 0) return 0;
  return 0.39 * (w.length / sentences.length) + 11.8 * (syllables / w.length) - 15.59;
}

export function scoreContent(html: string, plainText: string, targetKeyword: string, secondaryKeywords: string[], metaDescription: string): ContentScores {
  const wc = words(plainText).length;
  const kw = targetKeyword.toLowerCase();
  const textLower = plainText.toLowerCase();
  const first100 = words(textLower).slice(0, 100).join(" ");
  const kwCount = countOccurrences(textLower, kw);
  const density = wc > 0 ? (kwCount / wc) * 100 : 0;
  const grade = readabilityGrade(plainText);
  const sentences = plainText.split(/[.!?]+/).filter((s) => s.trim().length > 5);
  const paragraphs = plainText.split(/\n\n+/).filter((p) => p.trim().length > 0);

  // HTML analysis
  const h1Match = html.match(/<h1[^>]*>(.*?)<\/h1>/i);
  const h1Text = h1Match?.[1]?.toLowerCase() || "";
  const h2s = (html.match(/<h2[^>]*>/gi) || []).length;
  const h3s = (html.match(/<h3[^>]*>/gi) || []).length;
  const links = (html.match(/<a[^>]*href/gi) || []).length;
  const extLinks = (html.match(/<a[^>]*href=["']https?:\/\//gi) || []).length;
  const intLinks = links - extLinks;
  const imgAlts = (html.match(/<img[^>]*alt=["'][^"']+["']/gi) || []).length;
  const hasFaq = /faq|frequently asked|common questions/i.test(html);
  const hasLists = /<[ou]l[^>]*>/i.test(html);
  const hasTables = /<table/i.test(html);

  // ── SEO Score ──
  const seoFactors: ScoreFactor[] = [
    factor("Keyword in H1", kw && h1Text.includes(kw) ? 15 : 0, 15, `Add "${targetKeyword}" to your H1`),
    factor("Keyword in first 100 words", kw && first100.includes(kw) ? 10 : 0, 10, `Mention "${targetKeyword}" in the opening`),
    factor("Keyword density 0.5-2.5%", density >= 0.5 && density <= 2.5 ? 10 : density > 0 ? 5 : 0, 10, `Current: ${density.toFixed(1)}% — aim for 0.5-2.5%`),
    factor("Secondary keywords used", secondaryKeywords.length ? (secondaryKeywords.filter((k) => textLower.includes(k.toLowerCase())).length / secondaryKeywords.length >= 0.5 ? 10 : 5) : 10, 10, "Use more secondary keywords"),
    factor("Heading hierarchy", h1Match && h2s > 0 ? (h3s > 0 ? 10 : 7) : 0, 10, "Use H1 → H2 → H3 structure"),
    factor("Word count in range", wc >= 800 && wc <= 3000 ? 10 : wc >= 500 ? 5 : 0, 10, `${wc} words — aim for 800-2000`),
    factor("Internal links 2+", intLinks >= 2 ? 5 : intLinks >= 1 ? 3 : 0, 5, "Add internal links"),
    factor("External links 1+", extLinks >= 1 ? 5 : 0, 5, "Add an authoritative external link"),
    factor("Image alt text", imgAlts >= 1 ? 5 : 0, 5, "Add images with descriptive alt text"),
    factor("Meta description", metaDescription.length >= 150 && metaDescription.length <= 160 ? 5 : metaDescription.length >= 100 ? 3 : 0, 5, "Write 150-160 character meta description"),
    factor("Readability grade 6-8", grade >= 6 && grade <= 8 ? 10 : grade >= 4 && grade <= 10 ? 5 : 0, 10, `Grade ${grade.toFixed(1)} — aim for 6-8`),
    factor("PAA questions answered", hasFaq ? 5 : 0, 5, "Add an FAQ section"),
  ];

  // ── LLMO Score ──
  const shortSentences = sentences.filter((s) => words(s).length <= 20).length;
  const shortPct = sentences.length > 0 ? shortSentences / sentences.length : 0;
  const llmoFactors: ScoreFactor[] = [
    factor("Direct answer format", /^(the |a |an |it |this |here |yes|no)/im.test(plainText.slice(0, 200)) ? 15 : 0, 15, "Start with a direct answer"),
    factor("Structured content", hasLists || hasTables ? 10 : 0, 10, "Add lists or tables"),
    factor("FAQ section", hasFaq ? 10 : 0, 10, "Add FAQ section for AI citation"),
    factor("Authoritative language", /according to|research shows|studies|expert|certified|licensed/i.test(plainText) ? 10 : 0, 10, "Use authoritative language"),
    factor("Entity mentions", /\b[A-Z][a-z]+ [A-Z][a-z]+\b/.test(plainText) ? 10 : 0, 10, "Mention specific entities"),
    factor("Citation-worthy sentences", sentences.some((s) => s.length > 30 && s.length < 200 && /\d/.test(s)) ? 10 : 0, 10, "Include fact-based sentences with data"),
    factor("Freshness signals", /202[4-9]|updated|latest|current/i.test(plainText) ? 5 : 0, 5, "Include date/freshness signals"),
    factor("Expertise signals", /years of experience|board-certified|licensed|certified|award/i.test(plainText) ? 10 : 0, 10, "Add expertise credentials"),
    factor("Comparison/list format", /(best|top \d|vs\.?|versus|compared)/i.test(plainText) ? 10 : 0, 10, "Use comparison or ranking format"),
    factor("Speakable content", shortPct >= 0.6 ? 10 : shortPct >= 0.3 ? 5 : 0, 10, `${Math.round(shortPct * 100)}% short sentences — aim for 60%+`),
  ];

  // ── Humanization Score ──
  const humanFactors: ScoreFactor[] = [
    factor("Conversational tone", /you|your|we|our|let's/i.test(plainText) ? 15 : 0, 15, "Use 'you' and 'we' pronouns"),
    factor("Varied sentence length", sentences.length > 3 && new Set(sentences.map((s) => Math.floor(words(s).length / 5))).size >= 3 ? 15 : 5, 15, "Vary sentence lengths"),
    factor("No robotic patterns", !/in conclusion|it is important to note|furthermore/i.test(plainText) ? 10 : 0, 10, "Remove robotic transition phrases"),
    factor("Story/example elements", /for example|for instance|imagine|picture this|real-world|case study/i.test(plainText) ? 15 : 0, 15, "Add examples or stories"),
    factor("Active voice", !/is being|was being|has been|have been/.test(plainText.slice(0, 500)) ? 10 : 0, 10, "Use more active voice"),
    factor("Emotional language", /love|hate|amazing|terrible|exciting|frustrating|relief|stress/i.test(plainText) ? 10 : 0, 10, "Add emotional language"),
    factor("Questions to reader", /\?/.test(plainText) ? 10 : 0, 10, "Ask questions to engage readers"),
    factor("Natural transitions", /but |however |meanwhile |also |plus |and yet/i.test(plainText) ? 15 : 5, 15, "Use natural transition words"),
  ];

  const seoScore = seoFactors.reduce((s, f) => s + f.score, 0);
  const seoMax = seoFactors.reduce((s, f) => s + f.max, 0);
  const llmoScore = llmoFactors.reduce((s, f) => s + f.score, 0);
  const llmoMax = llmoFactors.reduce((s, f) => s + f.max, 0);
  const humanScore = humanFactors.reduce((s, f) => s + f.score, 0);
  const humanMax = humanFactors.reduce((s, f) => s + f.max, 0);

  const avgPct = ((seoScore / seoMax + llmoScore / llmoMax + humanScore / humanMax) / 3) * 100;
  const contentGrade = avgPct >= 90 ? "A+" : avgPct >= 85 ? "A" : avgPct >= 80 ? "A-" : avgPct >= 75 ? "B+" : avgPct >= 70 ? "B" : avgPct >= 65 ? "B-" : avgPct >= 60 ? "C+" : avgPct >= 55 ? "C" : avgPct >= 50 ? "C-" : avgPct >= 40 ? "D" : "F";

  return {
    seo: { score: seoScore, max: seoMax, factors: seoFactors },
    llmo: { score: llmoScore, max: llmoMax, factors: llmoFactors },
    human: { score: humanScore, max: humanMax, factors: humanFactors },
    grade: contentGrade,
    wordCount: wc,
    readingTime: Math.max(1, Math.round(wc / 238)),
    charCount: plainText.length,
    paragraphCount: paragraphs.length,
  };
}
