import "server-only";
import { getLegacyPosts, getLegacyPostBySlug, type LegacyPost } from "@/lib/legacy/content";
import { listPublishedBlogPosts, getPublishedBlogPostBySlug } from "@/lib/blog/queries";
import { topicFor, type Topic } from "@/lib/blog/topics";
import { renderVideoShortcodes } from "@/lib/blog/video-embed";
import { markdownToHtml } from "@/lib/blog/markdown";

/**
 * Canonical shape read by /blog/* pages, regardless of whether the content
 * comes from the legacy WordPress export bundle or the DB (admin-authored,
 * wp-migrate-imported). Lets the same template render both sources so there
 * is one URL pattern and one design.
 */
export type UnifiedPost = {
  id: string;
  slug: string;
  title: string;
  excerpt: string;
  /** ISO timestamp or null when missing. */
  date: string | null;
  featuredImage: string | null;
  html: string;
  tags: string[];
  topic: Topic;
  /** Used for JSON-LD `dateModified` + sorting. */
  modifiedAt: string | null;
  source: "db" | "legacy";
};

function legacyToUnified(p: LegacyPost): UnifiedPost {
  return {
    id: `legacy-${p.id}`,
    slug: p.slug,
    title: p.title || p.slug,
    excerpt: p.excerpt,
    date: p.date || null,
    featuredImage: p.featuredImage || null,
    html: p.html,
    tags: [],
    topic: topicFor(p),
    modifiedAt: p.date || null,
    source: "legacy",
  };
}

async function dbToUnified(
  row: Awaited<ReturnType<typeof listPublishedBlogPosts>>[number],
): Promise<UnifiedPost> {
  const fakePost = { title: row.title, excerpt: row.excerpt ?? "" };
  // Topic derived from tags first (migrator captures WP categories), then
  // falls back to keyword matching on title/excerpt.
  const tagBasedTopic = topicFromTags(row.tags ?? []);
  const topic = tagBasedTopic ?? topicFor(fakePost);
  const raw = row.content ?? "";
  const looksLikeHtml = /<(?:p|div|section|article|h[1-6]|ul|ol|figure|img|blockquote|a)\b/i.test(raw);
  // Migrated WP posts store HTML directly; admin-authored posts store markdown.
  const afterMarkdown = looksLikeHtml ? raw : markdownToHtml(raw);
  // Either way, expand any video shortcodes before the public template
  // runs DOMPurify.
  const html = renderVideoShortcodes(afterMarkdown);
  return {
    id: `db-${row.id}`,
    slug: row.slug,
    title: row.title,
    excerpt: row.excerpt ?? "",
    date: (row.publishedAt ?? row.createdAt)?.toISOString() ?? null,
    featuredImage: row.coverImage ?? null,
    html,
    tags: row.tags ?? [],
    topic,
    modifiedAt: (row.updatedAt ?? row.publishedAt ?? row.createdAt)?.toISOString() ?? null,
    source: "db",
  };
}

function topicFromTags(tags: string[]): Topic | null {
  const hay = tags.join(" ").toLowerCase();
  const check = (keys: string[]): boolean => keys.some((k) => hay.includes(k));
  if (check(["knee", "patell", "meniscus"])) return "Knee";
  if (check(["ankle", "foot", "achilles"])) return "Ankle & Foot";
  if (check(["shoulder", "rotator cuff", "clavicle"])) return "Shoulder";
  if (check(["elbow", "wrist", "hand"])) return "Elbow, Wrist & Hand";
  if (check(["hip", "femur", "acetabul"])) return "Hip";
  if (check(["spine", "neck", "back", "cervic", "lumbar"])) return "Spine & Neck";
  if (check(["paediatric", "pediatric", "child", "adolescent"])) return "Pediatric";
  if (check(["trauma", "fracture", "injury"])) return "Trauma";
  return null;
}

/**
 * Single authoritative lookup — DB rows take precedence over legacy so an
 * admin-edited post shadows any identically-slugged legacy entry.
 */
export async function getUnifiedPostBySlug(slug: string): Promise<UnifiedPost | null> {
  try {
    const dbRow = await getPublishedBlogPostBySlug(slug);
    if (dbRow) return dbToUnified(dbRow);
  } catch {
    /* fall through to legacy */
  }
  const legacy = getLegacyPostBySlug(slug);
  if (!legacy || legacy.type !== "post") return null;
  return legacyToUnified(legacy);
}

/**
 * Full list used by /blog, sitemap, related posts. DB posts first, then
 * legacy — deduped by slug.
 */
export async function listUnifiedPosts(): Promise<UnifiedPost[]> {
  let dbRows: Awaited<ReturnType<typeof listPublishedBlogPosts>> = [];
  try {
    dbRows = await listPublishedBlogPosts();
  } catch {
    dbRows = [];
  }
  const db = await Promise.all(dbRows.map(dbToUnified));
  const legacy = getLegacyPosts()
    .filter((p) => p.type === "post")
    .map(legacyToUnified);
  const seen = new Set(db.map((p) => p.slug));
  const merged = [...db];
  for (const l of legacy) if (!seen.has(l.slug)) merged.push(l);
  // Newest first by date (null sorts last).
  merged.sort((a, b) => {
    const ad = a.date ? new Date(a.date).getTime() : 0;
    const bd = b.date ? new Date(b.date).getTime() : 0;
    return bd - ad;
  });
  return merged;
}

export async function getAdjacentPosts(
  slug: string,
): Promise<{ prev: UnifiedPost | null; next: UnifiedPost | null }> {
  const all = await listUnifiedPosts();
  const index = all.findIndex((p) => p.slug === slug);
  if (index < 0) return { prev: null, next: null };
  return {
    prev: index > 0 ? all[index - 1] : null,
    next: index < all.length - 1 ? all[index + 1] : null,
  };
}

export async function getRelatedPosts(
  slug: string,
  topic: Topic,
  limit = 3,
): Promise<UnifiedPost[]> {
  const all = await listUnifiedPosts();
  return all
    .filter((p) => p.slug !== slug && p.topic === topic && p.featuredImage)
    .slice(0, limit);
}
