/**
 * Content scoring service.
 *
 * Calculates quality scores for SEO and LLMO content briefs.
 * Uses simple placeholder logic for now — replace with AI-powered
 * scoring when ready.
 *
 * All scores are 0–100.
 */

// ─── Types ───────────────────────────────────────────────────────────────────

export interface SeoScores {
  contentScore: number;
  keywordCoverage: number;
  internalLinkingStrength: number;
  contentStructure: number;
}

export interface LlmoScores {
  contentScore: number;
  conversationalDepth: number;
  longTailCoverage: number;
  answerReadyFormat: number;
}

interface BriefData {
  type: "seo" | "llmo";
  primaryKeyword?: string | null;
  secondaryKeywords?: string[];
  primaryTopic?: string | null;
  longTailKeywords?: string[];
  conversationalPhrases?: string[];
  relatedQuestions?: string[];
  sections?: unknown;
  internalLinks?: unknown;
  humanizationMode?: boolean;
}

// ─── Main scoring functions ──────────────────────────────────────────────────

/**
 * Score an SEO content brief.
 */
export function scoreSEOBrief(brief: BriefData): SeoScores {
  const sections = parseSections(brief.sections);
  const links = parseLinks(brief.internalLinks);

  const keywordCoverage = scoreKeywordCoverage(
    brief.primaryKeyword,
    brief.secondaryKeywords ?? [],
    sections
  );

  const internalLinkingStrength = scoreInternalLinking(links, sections);

  const contentStructure = scoreSeoStructure(sections);

  // Overall score is weighted average
  const contentScore = Math.round(
    keywordCoverage * 0.35 +
    internalLinkingStrength * 0.25 +
    contentStructure * 0.40
  );

  return { contentScore, keywordCoverage, internalLinkingStrength, contentStructure };
}

/**
 * Score an LLMO content brief.
 */
export function scoreLLMOBrief(brief: BriefData): LlmoScores {
  const sections = parseSections(brief.sections);

  const conversationalDepth = scoreConversationalDepth(
    sections,
    brief.relatedQuestions ?? [],
    brief.humanizationMode ?? false
  );

  const longTailCoverage = scoreLongTailCoverage(
    brief.primaryTopic,
    brief.longTailKeywords ?? [],
    brief.conversationalPhrases ?? [],
    sections
  );

  const answerReadyFormat = scoreAnswerReadyFormat(sections);

  // Overall score is weighted average
  const contentScore = Math.round(
    conversationalDepth * 0.30 +
    longTailCoverage * 0.30 +
    answerReadyFormat * 0.40
  );

  return { contentScore, conversationalDepth, longTailCoverage, answerReadyFormat };
}

/**
 * Score any brief (auto-detects type).
 */
export function scoreBrief(brief: BriefData): { contentScore: number; subScores: SeoScores | LlmoScores } {
  if (brief.type === "llmo") {
    const scores = scoreLLMOBrief(brief);
    return { contentScore: scores.contentScore, subScores: scores };
  }
  const scores = scoreSEOBrief(brief);
  return { contentScore: scores.contentScore, subScores: scores };
}

// ─── SEO sub-score logic ─────────────────────────────────────────────────────

function scoreKeywordCoverage(
  primary: string | null | undefined,
  secondary: string[],
  sections: Section[]
): number {
  let score = 0;
  const allContent = sections.map((s) => s.content.toLowerCase()).join(" ");

  // Primary keyword exists: +20
  if (primary) {
    score += 20;
    // Primary keyword appears in content: +30
    if (allContent.includes(primary.toLowerCase())) score += 30;
    // Primary keyword in H1 or title: +15
    const h1 = sections.find((s) => s.type === "h1" || s.type === "meta_title");
    if (h1 && h1.content.toLowerCase().includes(primary.toLowerCase())) score += 15;
  }

  // Secondary keywords used: up to +25
  if (secondary.length > 0) {
    const used = secondary.filter((kw) => allContent.includes(kw.toLowerCase()));
    score += Math.round((used.length / secondary.length) * 25);
  }

  // Has meta description: +10
  if (sections.some((s) => s.type === "meta_description")) score += 10;

  return Math.min(100, score);
}

function scoreInternalLinking(links: Link[], sections: Section[]): number {
  let score = 0;

  // Has any links: +30
  if (links.length > 0) score += 30;

  // 3+ links: +20
  if (links.length >= 3) score += 20;

  // 5+ links: +15
  if (links.length >= 5) score += 15;

  // Links have anchor text: +15
  const withAnchors = links.filter((l) => l.anchor && l.anchor.length > 3);
  if (withAnchors.length > 0) score += 15;

  // Content mentions links contextually: +20
  const allContent = sections.map((s) => s.content.toLowerCase()).join(" ");
  const contextual = links.filter((l) => allContent.includes(l.anchor.toLowerCase().slice(0, 10)));
  if (contextual.length > 0) score += Math.min(20, contextual.length * 5);

  return Math.min(100, score);
}

function scoreSeoStructure(sections: Section[]): number {
  let score = 0;

  // Has H1: +15
  if (sections.some((s) => s.type === "h1")) score += 15;

  // Has meta title: +10
  if (sections.some((s) => s.type === "meta_title")) score += 10;

  // Has meta description: +10
  if (sections.some((s) => s.type === "meta_description")) score += 10;

  // Has intro: +10
  if (sections.some((s) => s.type === "intro")) score += 10;

  // Has H2 sections: +15 (at least 2)
  const h2s = sections.filter((s) => s.type === "h2");
  if (h2s.length >= 1) score += 8;
  if (h2s.length >= 2) score += 7;

  // Has H3 subsections: +10
  if (sections.some((s) => s.type === "h3")) score += 10;

  // Has FAQ: +10
  if (sections.some((s) => s.type === "faq")) score += 10;

  // Has conclusion/CTA: +10
  if (sections.some((s) => s.type === "conclusion" || s.type === "cta")) score += 10;

  // Content length (more sections = better): up to +10
  score += Math.min(10, sections.length);

  return Math.min(100, score);
}

// ─── LLMO sub-score logic ────────────────────────────────────────────────────

function scoreConversationalDepth(
  sections: Section[],
  relatedQuestions: string[],
  humanized: boolean
): number {
  let score = 0;

  // Has conversational intro: +15
  if (sections.some((s) => s.type === "conversational_intro")) score += 15;

  // Has question sections: +20 (more = better)
  const questions = sections.filter((s) => s.type === "question");
  score += Math.min(20, questions.length * 7);

  // Has answer-first sections: +15
  if (sections.some((s) => s.type === "answer_first")) score += 15;

  // Related questions provided: +15
  if (relatedQuestions.length >= 3) score += 15;
  else if (relatedQuestions.length >= 1) score += 8;

  // Has insight sections: +10
  if (sections.some((s) => s.type === "insight")) score += 10;

  // Humanization mode bonus: +10
  if (humanized) score += 10;

  // Has summary: +10
  if (sections.some((s) => s.type === "summary")) score += 10;

  // Content length bonus: +5
  score += Math.min(5, sections.length);

  return Math.min(100, score);
}

function scoreLongTailCoverage(
  primaryTopic: string | null | undefined,
  longTailKeywords: string[],
  conversationalPhrases: string[],
  sections: Section[]
): number {
  let score = 0;
  const allContent = sections.map((s) => s.content.toLowerCase()).join(" ");

  // Has primary topic: +15
  if (primaryTopic) {
    score += 15;
    if (allContent.includes(primaryTopic.toLowerCase())) score += 15;
  }

  // Long-tail keywords provided: up to +30
  if (longTailKeywords.length > 0) {
    const used = longTailKeywords.filter((kw) => allContent.includes(kw.toLowerCase().slice(0, 15)));
    score += Math.min(30, Math.round((used.length / longTailKeywords.length) * 30));
  }

  // Conversational phrases provided: up to +25
  if (conversationalPhrases.length > 0) {
    score += Math.min(25, conversationalPhrases.length * 6);
  }

  // Has FAQ section (answers common queries): +15
  if (sections.some((s) => s.type === "faq")) score += 15;

  return Math.min(100, score);
}

function scoreAnswerReadyFormat(sections: Section[]): number {
  let score = 0;

  // Has answer-first sections (direct answers): +25
  const answers = sections.filter((s) => s.type === "answer_first");
  score += Math.min(25, answers.length * 12);

  // Has question sections (query-matching): +20
  const questions = sections.filter((s) => s.type === "question");
  score += Math.min(20, questions.length * 7);

  // Has FAQ section: +15
  if (sections.some((s) => s.type === "faq")) score += 15;

  // Has conversational intro: +10
  if (sections.some((s) => s.type === "conversational_intro")) score += 10;

  // Has summary (concise takeaway): +10
  if (sections.some((s) => s.type === "summary")) score += 10;

  // Content is structured (3+ sections): +10
  if (sections.length >= 3) score += 10;

  // Bonus for insight sections: +10
  if (sections.some((s) => s.type === "insight")) score += 10;

  return Math.min(100, score);
}

// ─── Helpers ─────────────────────────────────────────────────────────────────

interface Section {
  type: string;
  content: string;
}

interface Link {
  anchor: string;
  targetUrl?: string;
  anchorText?: string;
}

function parseSections(raw: unknown): Section[] {
  if (!raw) return [];
  try {
    const arr = typeof raw === "string" ? JSON.parse(raw) : raw;
    if (!Array.isArray(arr)) return [];
    return arr.map((s: Record<string, unknown>) => ({
      type: String(s.type || ""),
      content: String(s.content || s.heading || ""),
    }));
  } catch {
    return [];
  }
}

function parseLinks(raw: unknown): Link[] {
  if (!raw) return [];
  try {
    const arr = typeof raw === "string" ? JSON.parse(raw) : raw;
    if (!Array.isArray(arr)) return [];
    return arr.map((l: Record<string, unknown>) => ({
      anchor: String(l.anchorText || l.anchor || ""),
      targetUrl: String(l.targetUrl || l.targetPage || ""),
    }));
  } catch {
    return [];
  }
}
