/**
 * Build-time generation of the Ghost-backed blog.
 *
 * Runs under Node from vite.config.ts. For each post tagged `lynkeduppro-new`
 * it writes blog/<slug>/index.html from the shared shell template, so every post
 * ships as real static HTML with its SEO tags present in the source.
 */

import fs from "node:fs";
import path from "node:path";
import { fetchSitePosts, readGhostConfig } from "./client";
import { normalizePosts } from "./normalize";
import { renderPostCard, renderPostPage } from "./render";
import type { BlogPost } from "./types";

const BLOG_DIR = path.resolve("blog");
const TEMPLATE_PATH = path.join(BLOG_DIR, "_post.template.html");
const MANIFEST_PATH = path.join(BLOG_DIR, ".ghost-generated.json");

/**
 * Hand-authored posts that predate the Ghost integration. They own their routes:
 * their directories are never generated or removed, and a Ghost post reusing one
 * of these slugs is skipped rather than overwriting the static page.
 */
export const STATIC_POST_SLUGS = [
  "cost-of-paperwork",
  "48-hour-storm-checklist",
  "why-claims-get-denied",
];

export interface GhostBuildResult {
  posts: BlogPost[];
  /** Rendered cards for injection into blog/index.html. */
  cardsHtml: string;
  /** Absolute paths of generated pages, for Vite's rollup inputs. */
  generatedPages: string[];
}

/** Removes pages generated by a previous run so deleted/untagged posts disappear. */
function cleanPreviousRun(): void {
  let previous: string[] = [];
  try {
    previous = JSON.parse(fs.readFileSync(MANIFEST_PATH, "utf8")) as string[];
  } catch {
    return;
  }
  for (const slug of previous) {
    if (STATIC_POST_SLUGS.includes(slug)) continue;
    fs.rmSync(path.join(BLOG_DIR, slug), { recursive: true, force: true });
  }
}

/**
 * Fetches, renders and writes every Ghost post for this site.
 *
 * @param allowStaleFallback Use the last cached response if Ghost is unreachable
 *   (dev only).
 */
export async function buildGhostBlog(
  env: Record<string, string | undefined>,
  { allowStaleFallback = false }: { allowStaleFallback?: boolean } = {}
): Promise<GhostBuildResult> {
  const config = readGhostConfig(env);
  const raw = await fetchSitePosts(config, { allowStaleFallback });
  const posts = normalizePosts(raw, config, STATIC_POST_SLUGS);

  const skipped = raw.length - posts.length;
  if (skipped > 0) {
    console.warn(
      `[ghost] skipped ${skipped} post(s): slug missing, or colliding with a static post ` +
        `(${STATIC_POST_SLUGS.join(", ")}).`
    );
  }

  cleanPreviousRun();

  const template = fs.readFileSync(TEMPLATE_PATH, "utf8");
  const generatedPages: string[] = [];

  posts.forEach((post, i) => {
    const dir = path.join(BLOG_DIR, post.slug);
    const file = path.join(dir, "index.html");
    fs.mkdirSync(dir, { recursive: true });
    fs.writeFileSync(file, renderPostPage(template, post, posts[i + 1] ?? null), "utf8");
    generatedPages.push(file);
  });

  fs.writeFileSync(MANIFEST_PATH, JSON.stringify(posts.map((p) => p.slug), null, 2), "utf8");

  console.log(
    `[ghost] generated ${posts.length} post page(s) from tag "lynkeduppro-new"` +
      (posts.length ? `: ${posts.map((p) => p.slug).join(", ")}` : "")
  );

  return {
    posts,
    cardsHtml: posts.map(renderPostCard).join("\n\n"),
    generatedPages,
  };
}
