/**
 * Analysis checks — TypeScript port of Rank Math's
 * assets/admin/src/analyzer/analysis/*.js (25 individual tests).
 *
 * Each check is a pure function that takes a Paper and returns an
 * AnalysisResult (or null if the check is not applicable). Scoring
 * weights mirror Rank Math's defaults so a perfect article still hits ~100.
 *
 * Adaptations for Finzone v2:
 *   • Vietnamese readability defaults (locale: "vi" treats one whitespace
 *     token ≈ one syllable so we don't punish Vietnamese articles).
 *   • Markdown-aware (we strip Markdown to plain text before counting).
 *   • Removed WordPress filter hooks (`applyFilters`) — the user can fork
 *     boundaries directly here.
 *   • Sentiment / power-word lists are Vietnamese.
 */

import type { AnalysisCheck, AnalysisResult, Paper, ScoreType } from "./types";
import { countMatches, escapeRegex, keywordCombinations } from "./text";

function result(
  partial: Omit<AnalysisResult, "type" | "text" | "tooltip"> & {
    text: string;
    tooltip?: string;
  },
): AnalysisResult {
  const ratio = partial.maxScore === 0 ? 1 : partial.score / partial.maxScore;
  let type: ScoreType;
  if (partial.score === 0) type = "fail";
  else if (ratio >= 1) type = "best";
  else if (ratio >= 0.66) type = "good";
  else if (ratio >= 0.33) type = "fair";
  else type = "fail";
  return { ...partial, type, tooltip: partial.tooltip };
}

// =====================================================================
// Title checks
// =====================================================================

export const keywordInTitle: AnalysisCheck = (paper) => {
  if (!paper.keyword || !paper.metaTitle) return null;
  const has = paper.metaTitle.toLowerCase().includes(paper.keyword.toLowerCase());
  return result({
    id: "keywordInTitle",
    title: "Từ khóa xuất hiện ở SEO Title",
    score: has ? 38 : 0,
    maxScore: 38,
    severity: 10,
    text: has
      ? "Tốt! Từ khóa đã có trong SEO Title."
      : "Từ khóa chưa xuất hiện trong SEO Title — thêm vào để tăng điểm SEO.",
  });
};

export const keywordInMetaDescription: AnalysisCheck = (paper) => {
  if (!paper.keyword) return null;
  const has =
    paper.metaDesc && paper.metaDesc.toLowerCase().includes(paper.keyword.toLowerCase());
  return result({
    id: "keywordInMetaDescription",
    title: "Từ khóa xuất hiện ở Meta Description",
    score: has ? 6 : 0,
    maxScore: 6,
    severity: 8,
    text: has
      ? "Meta Description đã chứa từ khóa."
      : "Thêm từ khóa vào Meta Description để tăng CTR.",
  });
};

export const keywordInPermalink: AnalysisCheck = (paper) => {
  if (!paper.keyword || !paper.slug) return null;
  // Slug is already kebab-case, keyword may have spaces — compare loosely
  const slugTokens = paper.slug.toLowerCase();
  const kw = paper.keyword.toLowerCase().replace(/\s+/g, "-");
  const hasFull = slugTokens.includes(kw);
  const hasPart = paper.keyword
    .toLowerCase()
    .split(/\s+/)
    .some((p) => p.length >= 3 && slugTokens.includes(p));
  return result({
    id: "keywordInPermalink",
    title: "Từ khóa có trong URL slug",
    score: hasFull ? 6 : hasPart ? 3 : 0,
    maxScore: 6,
    severity: 7,
    text: hasFull
      ? "Slug đã chứa từ khóa đầy đủ."
      : hasPart
        ? "Slug chỉ chứa một phần của từ khóa — cân nhắc viết lại."
        : "Slug chưa chứa từ khóa nào.",
  });
};

export const keywordIn10Percent: AnalysisCheck = (paper) => {
  if (!paper.keyword || !paper.text) return null;
  const text = paper.text.toLowerCase();
  const first10 = text.slice(0, Math.max(120, Math.floor(text.length * 0.1)));
  const has = first10.includes(paper.keyword.toLowerCase());
  return result({
    id: "keywordIn10Percent",
    title: "Từ khóa xuất hiện ở 10% đầu nội dung",
    score: has ? 7 : 0,
    maxScore: 7,
    severity: 8,
    text: has
      ? "Mở bài đã đề cập từ khóa — Google ưu tiên."
      : "Đặt từ khóa trong vài câu đầu để tín hiệu rõ ràng hơn.",
  });
};

export const keywordInSubheadings: AnalysisCheck = (paper) => {
  if (!paper.keyword || paper.subheadings.length === 0) return null;
  const has = paper.subheadings.some((h) =>
    h.toLowerCase().includes(paper.keyword.toLowerCase()),
  );
  return result({
    id: "keywordInSubheadings",
    title: "Từ khóa xuất hiện ở Subheadings (H2/H3)",
    score: has ? 5 : 0,
    maxScore: 5,
    severity: 5,
    text: has
      ? "Một subheading đã chứa từ khóa."
      : "Thêm từ khóa vào ít nhất một H2/H3 để đẩy ngữ nghĩa.",
  });
};

export const keywordInImageAlt: AnalysisCheck = (paper) => {
  if (!paper.keyword) return null;
  if (paper.images.length === 0 && !paper.coverImage) return null;
  const allAlts = [paper.coverAlt ?? "", ...paper.images.map((i) => i.alt)];
  const has = allAlts.some((alt) =>
    alt && alt.toLowerCase().includes(paper.keyword.toLowerCase()),
  );
  return result({
    id: "keywordInImageAlt",
    title: "Từ khóa có trong Image Alt",
    score: has ? 4 : 0,
    maxScore: 4,
    severity: 4,
    text: has
      ? "Một ảnh có alt chứa từ khóa."
      : "Thêm từ khóa vào alt của ảnh đại diện hoặc ảnh trong bài.",
  });
};

// =====================================================================
// Density / coverage
// =====================================================================

export const keywordDensity: AnalysisCheck = (paper) => {
  const text = paper.text.toLowerCase();
  const words = text.split(/\s+/).filter(Boolean).length;
  if (!paper.keyword || words === 0) return null;
  const combos = keywordCombinations(paper.keyword);
  const re = new RegExp(combos.map(escapeRegex).join("|"), "gi");
  const count = (paper.text.match(re) ?? []).length;
  const density = (count / words) * 100;

  // Rank Math boundaries: <0.5 fail, 0.5-0.75 fair, 0.76-1 good, 1-2.5 best, >2.5 fail
  let score = 0;
  let msg = "";
  if (density < 0.5) {
    score = 0;
    msg = `Mật độ từ khóa thấp (${density.toFixed(2)}%, xuất hiện ${count} lần).`;
  } else if (density < 0.75) {
    score = 2;
    msg = `Mật độ từ khóa hơi thấp (${density.toFixed(2)}%, ${count} lần).`;
  } else if (density <= 1) {
    score = 3;
    msg = `Mật độ từ khóa khá tốt (${density.toFixed(2)}%, ${count} lần).`;
  } else if (density <= 2.5) {
    score = 6;
    msg = `Mật độ từ khóa lý tưởng (${density.toFixed(2)}%, ${count} lần).`;
  } else {
    score = 0;
    msg = `Mật độ từ khóa quá cao (${density.toFixed(2)}%, ${count} lần) — có thể bị xem là spam.`;
  }
  return result({
    id: "keywordDensity",
    title: "Mật độ từ khóa",
    score,
    maxScore: 6,
    severity: 6,
    text: msg,
  });
};

// =====================================================================
// Length
// =====================================================================

export const lengthContent: AnalysisCheck = (paper) => {
  const words = paper.text.split(/\s+/).filter(Boolean).length;
  let score = 0;
  let msg = "";
  if (words < 300) {
    score = 0;
    msg = `Bài chỉ có ${words} từ — quá ngắn (mục tiêu 800+).`;
  } else if (words < 600) {
    score = 4;
    msg = `Bài có ${words} từ — chấp nhận được, có thể mở rộng.`;
  } else if (words < 1500) {
    score = 7;
    msg = `Bài có ${words} từ — tốt cho SEO.`;
  } else {
    score = 7;
    msg = `Bài dài ${words} từ — rất tốt cho long-tail.`;
  }
  return result({
    id: "lengthContent",
    title: "Độ dài nội dung",
    score,
    maxScore: 7,
    severity: 7,
    text: msg,
  });
};

export const lengthPermalink: AnalysisCheck = (paper) => {
  if (!paper.slug) return null;
  const len = paper.slug.length;
  let score = 0;
  let msg = "";
  if (len <= 75) {
    score = 4;
    msg = `Slug dài ${len} ký tự — gọn gàng.`;
  } else if (len <= 110) {
    score = 2;
    msg = `Slug dài ${len} ký tự — hơi dài.`;
  } else {
    score = 0;
    msg = `Slug dài ${len} ký tự — quá dài, nên rút gọn.`;
  }
  return result({
    id: "lengthPermalink",
    title: "Độ dài URL slug",
    score,
    maxScore: 4,
    severity: 4,
    text: msg,
  });
};

// =====================================================================
// Links
// =====================================================================

export const linksHasInternal: AnalysisCheck = (paper) => {
  const has = paper.internalLinks.length > 0;
  return result({
    id: "linksHasInternal",
    title: "Có internal link",
    score: has ? 5 : 0,
    maxScore: 5,
    severity: 6,
    text: has
      ? `Bài có ${paper.internalLinks.length} liên kết nội bộ.`
      : "Thêm ít nhất 1 internal link để tăng kết nối nội dung.",
  });
};

export const linksHasExternals: AnalysisCheck = (paper) => {
  const has = paper.externalLinks.length > 0;
  return result({
    id: "linksHasExternals",
    title: "Có external link",
    score: has ? 4 : 0,
    maxScore: 4,
    severity: 4,
    text: has
      ? `Bài có ${paper.externalLinks.length} liên kết ngoài (citation tốt cho EAT).`
      : "Thêm liên kết ngoài tới nguồn uy tín (Reuters, Bloomberg, …).",
  });
};

export const linksNotAllExternals: AnalysisCheck = (paper) => {
  if (paper.internalLinks.length + paper.externalLinks.length === 0) return null;
  const allExt =
    paper.externalLinks.length > 0 && paper.internalLinks.length === 0;
  return result({
    id: "linksNotAllExternals",
    title: "Không phải toàn external link",
    score: allExt ? 0 : 2,
    maxScore: 2,
    severity: 3,
    text: allExt
      ? "Bài chỉ có external link — cân bằng thêm internal."
      : "Cân bằng internal/external tốt.",
  });
};

// =====================================================================
// Title quality
// =====================================================================

export const titleStartWithKeyword: AnalysisCheck = (paper) => {
  if (!paper.keyword || !paper.metaTitle) return null;
  const start = paper.metaTitle.toLowerCase().slice(0, paper.keyword.length + 5);
  const startsWith = start.startsWith(paper.keyword.toLowerCase());
  return result({
    id: "titleStartWithKeyword",
    title: "SEO Title bắt đầu bằng từ khóa",
    score: startsWith ? 3 : 1,
    maxScore: 3,
    severity: 3,
    text: startsWith
      ? "Title bắt đầu bằng từ khóa — tối ưu CTR."
      : "Cân nhắc đặt từ khóa ở đầu Title.",
  });
};

export const titleHasNumber: AnalysisCheck = (paper) => {
  if (!paper.metaTitle) return null;
  const hasNum = /\d/.test(paper.metaTitle);
  return result({
    id: "titleHasNumber",
    title: "Title có chứa số",
    score: hasNum ? 1 : 0,
    maxScore: 1,
    severity: 2,
    text: hasNum
      ? "Title có số — title dạng listicle thường có CTR cao hơn."
      : 'Cân nhắc thêm số (ví dụ: "5 cách…", "2026").',
  });
};

const POWER_WORDS_VI = [
  "bí mật", "sốc", "bất ngờ", "chấn động", "kinh ngạc", "đáng kinh ngạc",
  "miễn phí", "dễ dàng", "nhanh chóng", "ngay lập tức", "cực kỳ", "siêu",
  "tốt nhất", "đỉnh", "đỉnh cao", "tuyệt đỉnh", "chuyên gia", "chuyên sâu",
  "đột phá", "mới nhất", "độc quyền", "duy nhất", "hiếm có", "quan trọng",
  "đắt giá", "vô giá", "hot", "nóng hổi",
];

export const titleHasPowerWords: AnalysisCheck = (paper) => {
  if (!paper.metaTitle) return null;
  const lower = paper.metaTitle.toLowerCase();
  const matched = POWER_WORDS_VI.filter((w) => lower.includes(w));
  return result({
    id: "titleHasPowerWords",
    title: "Title có Power Words",
    score: matched.length > 0 ? 2 : 0,
    maxScore: 2,
    severity: 2,
    text:
      matched.length > 0
        ? `Title chứa power word: ${matched.join(", ")}.`
        : "Thêm power word để Title hấp dẫn hơn (bí mật, sốc, miễn phí…).",
  });
};

const POSITIVE_VI = ["tốt", "tăng", "thành công", "hiệu quả", "tuyệt", "lợi", "vững", "ổn định"];
const NEGATIVE_VI = ["xấu", "giảm", "thất bại", "rủi ro", "tệ", "lỗ", "sụp đổ", "khủng hoảng"];

export const titleSentiment: AnalysisCheck = (paper) => {
  if (!paper.metaTitle) return null;
  const lower = paper.metaTitle.toLowerCase();
  const pos = POSITIVE_VI.some((w) => lower.includes(w));
  const neg = NEGATIVE_VI.some((w) => lower.includes(w));
  const hasSentiment = pos || neg;
  return result({
    id: "titleSentiment",
    title: "Title có cảm xúc (positive/negative)",
    score: hasSentiment ? 1 : 0,
    maxScore: 1,
    severity: 2,
    text: hasSentiment
      ? "Title đã có hàm ý cảm xúc — kích thích click."
      : "Cân nhắc dùng từ mang cảm xúc (tăng/giảm/thành công/…).",
  });
};

// =====================================================================
// Structure
// =====================================================================

export const contentHasShortParagraphs: AnalysisCheck = (paper) => {
  if (!paper.text) return null;
  const paragraphs = paper.text
    .split(/\n\s*\n/)
    .map((p) => p.trim())
    .filter(Boolean);
  if (paragraphs.length === 0) return null;
  const long = paragraphs.filter((p) => p.split(/\s+/).length > 150);
  const ratio = long.length / paragraphs.length;
  return result({
    id: "contentHasShortParagraphs",
    title: "Đoạn văn ngắn (≤150 từ)",
    score: ratio === 0 ? 3 : ratio < 0.2 ? 2 : 0,
    maxScore: 3,
    severity: 4,
    text:
      long.length === 0
        ? "Tất cả đoạn văn đều dưới 150 từ — dễ đọc."
        : `Có ${long.length}/${paragraphs.length} đoạn dài hơn 150 từ — chia nhỏ ra.`,
  });
};

export const contentHasAssets: AnalysisCheck = (paper) => {
  const total = paper.images.length + (paper.coverImage ? 1 : 0);
  return result({
    id: "contentHasAssets",
    title: "Có ảnh / video minh họa",
    score: total === 0 ? 0 : total >= 2 ? 3 : 2,
    maxScore: 3,
    severity: 4,
    text:
      total === 0
        ? "Bài chưa có ảnh nào — Google ưu tiên bài có visual."
        : `Bài có ${total} hình ảnh.`,
  });
};

export const contentHasTOC: AnalysisCheck = (paper) => {
  const has = paper.subheadings.length >= 3;
  return result({
    id: "contentHasTOC",
    title: "Có cấu trúc Table of Contents (≥3 H2/H3)",
    score: has ? 3 : 0,
    maxScore: 3,
    severity: 4,
    text: has
      ? `Bài có ${paper.subheadings.length} subheadings — đủ để render TOC tự động.`
      : "Thêm subheadings (H2/H3) để bài có cấu trúc rõ ràng.",
  });
};

export const allChecks: Record<string, AnalysisCheck> = {
  keywordInTitle,
  keywordInMetaDescription,
  keywordInPermalink,
  keywordIn10Percent,
  keywordInSubheadings,
  keywordInImageAlt,
  keywordDensity,
  lengthContent,
  lengthPermalink,
  linksHasInternal,
  linksHasExternals,
  linksNotAllExternals,
  titleStartWithKeyword,
  titleHasNumber,
  titleHasPowerWords,
  titleSentiment,
  contentHasShortParagraphs,
  contentHasAssets,
  contentHasTOC,
};
