import { prisma } from "@/lib/db";
import { chat, loadAiConfig } from "@/lib/ai/openai";

/**
 * Image SEO — auto-generate `alt` text for media items.
 *
 * Strategy (no Vision API needed):
 *   1. Find articles that reference this image (by URL or filename) — extract
 *      title + the surrounding paragraph.
 *   2. Fall back to filename heuristics (un-slugify, strip extension/numbers).
 *   3. If AI is configured (Setting ai.openai_*), use it to refine the heuristic
 *      result into a concise, descriptive Vietnamese alt (≤125 chars).
 *
 * Returns both the suggestion and the source so the UI can label the result.
 */

export type AltSource = "ai" | "context" | "filename" | "none";

export interface AltSuggestion {
  alt: string;
  source: AltSource;
  /** Articles that reference this image (for the UI to show) */
  usedBy: Array<{ slug: string; title: string }>;
}

function unslugify(filename: string): string {
  // strip path + extension
  const base = filename.replace(/^.*\//, "").replace(/\.[a-z0-9]+$/i, "");
  return base
    .replace(/[-_]+/g, " ")
    .replace(/\b\d{4,}\b/g, "") // year/timestamp
    .replace(/\b\d+\b/g, "") // any leftover number
    .replace(/\b(IMG|DSC|PIC|photo|image|img|screenshot|cover|truonggiang)\b/gi, "")
    .replace(/\s+/g, " ")
    .trim();
}

/**
 * Decide if a heuristic alt is "good enough" — meaningful Vietnamese/English words.
 * Filters out filenames that look like camera output (DSC1234, IMG_001) or have
 * fewer than 2 real words.
 */
function isMeaningfulHeuristic(s: string): boolean {
  if (s.length < 6) return false;
  const tokens = s.split(/\s+/).filter((t) => t.length >= 3 && /[a-zà-ỹ]/i.test(t));
  return tokens.length >= 2;
}

/**
 * Build a heuristic alt from filename ALONE.
 * Returns "" when filename has nothing meaningful (e.g. "img-001.jpg").
 */
export function heuristicAlt(filename: string): string {
  const fromName = unslugify(filename);
  if (!fromName) return "";
  const cleaned = fromName
    .replace(/[#*_`>]+/g, "")
    .replace(/\s+/g, " ")
    .trim()
    .slice(0, 125);
  if (!cleaned) return "";
  return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
}

function altFromTitle(title: string): string {
  const cleaned = title
    .replace(/[#*_`>]+/g, "")
    .replace(/\s+/g, " ")
    .trim()
    .slice(0, 125);
  if (!cleaned) return "";
  return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
}

/**
 * Find article(s) that reference this image URL or filename.
 */
export async function findImageUsage(media: {
  url: string;
  filename: string;
}): Promise<Array<{ slug: string; title: string; snippet: string }>> {
  // Search Article.content for the URL or filename.
  // We use raw substring matches because Postgres ILIKE on a TEXT column with
  // a LIKE-friendly pattern is fast enough for our scale.
  const variants = [media.url, `/${media.filename}`, media.filename]
    .filter(Boolean)
    .map((s) => s.replace(/^https?:\/\//, ""));
  const orFilters = variants.flatMap((v) => [
    { content: { contains: v } },
    { coverImage: { contains: v } },
  ]);

  const rows = await prisma.article.findMany({
    where: { OR: orFilters },
    take: 5,
    orderBy: { updatedAt: "desc" },
    select: { slug: true, title: true, content: true },
  });

  return rows.map((r) => {
    let snippet = "";
    if (r.content) {
      const idx =
        variants
          .map((v) => r.content.indexOf(v))
          .find((i) => i >= 0) ?? -1;
      if (idx >= 0) {
        const start = Math.max(0, idx - 200);
        const end = Math.min(r.content.length, idx + 200);
        snippet = r.content.slice(start, end).replace(/\s+/g, " ").trim();
      }
    }
    return { slug: r.slug, title: r.title, snippet };
  });
}

/**
 * Refine a heuristic alt with AI (if configured). Falls back to the heuristic
 * when no AI provider or on error.
 */
async function refineWithAi(input: {
  heuristic: string;
  filename: string;
  contextTitle?: string;
  contextSnippet?: string;
}): Promise<{ alt: string; source: AltSource } | null> {
  const cfg = await loadAiConfig();
  if (!cfg) return null;

  const sys =
    "Bạn là biên tập SEO viết alt text cho ảnh trên website tin tài chính tiếng Việt. " +
    "Trả về MỘT dòng alt ngắn gọn (≤125 ký tự), không dấu nháy, không từ thừa, không kết thúc bằng dấu chấm.";
  const userMsg = [
    `Tên file: ${input.filename}`,
    input.contextTitle ? `Tiêu đề bài: ${input.contextTitle}` : "",
    input.contextSnippet ? `Đoạn liên quan: ${input.contextSnippet.slice(0, 500)}` : "",
    `Gợi ý heuristic: ${input.heuristic}`,
    "",
    "Trả về duy nhất alt text, không giải thích, không quote.",
  ]
    .filter(Boolean)
    .join("\n");

  try {
    const result = await chat(cfg, [
      { role: "system", content: sys },
      { role: "user", content: userMsg },
    ], { temperature: 0.3, maxTokens: 80 });
    const cleaned = result.content
      .replace(/^["'`]+|["'`.]+$/g, "")
      .replace(/^[Aa]lt\s*[:：]\s*/, "")
      .replace(/\s+/g, " ")
      .trim()
      .slice(0, 125);
    if (cleaned.length >= 4) return { alt: cleaned, source: "ai" };
  } catch {
    // fall through
  }
  return null;
}

/**
 * Public API — generate an alt suggestion for a single media item.
 *
 * Source labels reflect the FINAL alt text origin:
 *   - "ai" — refined by an LLM
 *   - "context" — heuristic from filename, but enriched/biased by the title
 *                 of the article that uses this image
 *   - "filename" — pure filename heuristic (no article context found)
 *   - "none" — couldn't produce anything useful
 */
export async function generateAltForMedia(media: {
  id: string;
  url: string;
  filename: string;
}): Promise<AltSuggestion> {
  const usage = await findImageUsage(media);
  const ctxTitle = usage[0]?.title ?? "";
  const ctxSnippet = usage[0]?.snippet ?? "";

  const heuristic = heuristicAlt(media.filename);

  // Try AI refinement first when configured
  const aiResult = await refineWithAi({
    heuristic: heuristic || ctxTitle,
    filename: media.filename,
    contextTitle: ctxTitle,
    contextSnippet: ctxSnippet,
  });

  let alt: string;
  let source: AltSource;
  if (aiResult) {
    alt = aiResult.alt;
    source = "ai";
  } else if (heuristic && isMeaningfulHeuristic(heuristic)) {
    // Filename has 2+ real words — trust it
    alt = heuristic;
    source = "filename";
  } else if (ctxTitle) {
    // Filename is junk (DSC1234 / camera output) — substitute article title
    alt = altFromTitle(ctxTitle);
    source = "context";
  } else if (heuristic) {
    // Last resort: use whatever the filename gave us
    alt = heuristic;
    source = "filename";
  } else {
    alt = "";
    source = "none";
  }

  return {
    alt,
    source,
    usedBy: usage.map(({ slug, title }) => ({ slug, title })),
  };
}
