import { prisma } from "@/lib/db";

/**
 * Internal Link Suggestions — port of Rank Math's "Internal Linking" feature.
 *
 * Given a draft article (title + content), find up to N other published
 * articles whose focusKeyword / metaKeywords / title overlap with the draft's
 * subheadings or focus keyword, and aren't already linked.
 *
 * Strategy:
 *  1. Pull recent published articles (sample up to 200 most recent).
 *  2. Score each by overlap: focusKeyword match (3pt), title token overlap (1pt
 *     per matching token >=4 chars), category match (2pt).
 *  3. Skip articles already linked from the draft (`/{slug}` appears in body).
 *  4. Return top N by score.
 */

export interface LinkSuggestion {
  slug: string;
  title: string;
  excerpt: string | null;
  score: number;
  reason: string;
}

export async function suggestInternalLinks(input: {
  draftTitle: string;
  draftContent: string;
  draftFocusKeyword?: string | null;
  draftCategorySlug?: string | null;
  excludeSlug?: string | null;
  limit?: number;
}): Promise<LinkSuggestion[]> {
  const limit = input.limit ?? 8;

  const articles = await prisma.article.findMany({
    where: {
      status: "published",
      ...(input.excludeSlug ? { slug: { not: input.excludeSlug } } : {}),
    },
    orderBy: { publishedAt: "desc" },
    take: 200,
    select: {
      slug: true,
      title: true,
      excerpt: true,
      focusKeyword: true,
      category: { select: { slug: true } },
    },
  });

  const linkedRe = /\(\/([a-z0-9-]+)\)/gi;
  const alreadyLinked = new Set<string>();
  let m: RegExpExecArray | null;
  while ((m = linkedRe.exec(input.draftContent)) !== null) alreadyLinked.add(m[1]);

  const draftLower = input.draftContent.toLowerCase();
  const draftTitleLower = input.draftTitle.toLowerCase();

  const scored: LinkSuggestion[] = [];
  for (const a of articles) {
    if (alreadyLinked.has(a.slug)) continue;

    let score = 0;
    const reasons: string[] = [];

    if (a.focusKeyword) {
      const fkLower = a.focusKeyword.toLowerCase();
      if (draftLower.includes(fkLower)) {
        score += 3;
        reasons.push(`từ khóa "${a.focusKeyword}"`);
      } else if (draftTitleLower.includes(fkLower)) {
        score += 2;
        reasons.push(`từ khóa "${a.focusKeyword}" trong tiêu đề`);
      }
    }

    const titleTokens = a.title
      .toLowerCase()
      .split(/[^a-zàáạảãâầấậẩẫăằắặẳẵèéẹẻẽêềếệểễìíịỉĩòóọỏõôồốộổỗơờớợởỡùúụủũưừứựửữỳýỵỷỹđ0-9]+/u)
      .filter((t) => t.length >= 4);
    let tokenHits = 0;
    for (const t of titleTokens) {
      if (draftLower.includes(t)) tokenHits++;
    }
    if (tokenHits > 0) {
      score += Math.min(3, tokenHits);
      reasons.push(`${tokenHits} từ trùng tiêu đề`);
    }

    if (
      input.draftCategorySlug &&
      a.category?.slug &&
      a.category.slug === input.draftCategorySlug
    ) {
      score += 2;
      reasons.push("cùng chuyên mục");
    }

    if (score > 0) {
      scored.push({
        slug: a.slug,
        title: a.title,
        excerpt: a.excerpt,
        score,
        reason: reasons.join(" · "),
      });
    }
  }

  scored.sort((a, b) => b.score - a.score);
  return scored.slice(0, limit);
}
