import 'server-only';
import { readFile } from 'node:fs/promises';
import path from 'node:path';
import { z } from 'zod';

// This module is the entire "fix a mistake without a CMS" story for the
// site. Instead of a dashboard, a human edits config/overrides.json
// (a plain, version-controlled file) and the scheduled jobs in
// src/app/api/cron/* read it on every run. Concretely:
//
//   - excludedSlugs   -> immediately de-indexed & skipped by every job
//   - forceRegenerate -> content is rebuilt (and cleared from this list)
//                        on the next `generate-content` run
//   - pinnedFacts     -> a manual correction that overrides whatever the
//                        source APIs say for that field, until the
//                        override is removed
//   - featuredSlugs   -> pins games to the top of directory/homepage rails
//
// This is intentionally a file, not a database table: fixing a mistake
// should be a one-line git diff a human can review, not a write path
// that needs its own auth/UI.

const PinnedFactsSchema = z.record(
  z.string(), // slug
  z.object({
    name: z.string().optional(),
    releaseDate: z.string().optional(), // ISO date, overrides source data
    summary: z.string().optional(),
    coverUrl: z.string().url().optional(),
  }),
);

const OverridesSchema = z.object({
  excludedSlugs: z.array(z.string()).default([]),
  forceRegenerate: z.array(z.string()).default([]),
  pinnedFacts: PinnedFactsSchema.default({}),
  featuredSlugs: z.array(z.string()).default([]),
});

export type Overrides = z.infer<typeof OverridesSchema>;

const OVERRIDES_PATH = path.join(process.cwd(), 'config', 'overrides.json');

let cache: { data: Overrides; loadedAt: number } | null = null;
const CACHE_TTL_MS = 30_000; // short TTL: cheap to re-read, and cron jobs
// should see edits quickly without a redeploy.

export async function loadOverrides(): Promise<Overrides> {
  const now = Date.now();
  if (cache && now - cache.loadedAt < CACHE_TTL_MS) {
    return cache.data;
  }

  try {
    const raw = await readFile(OVERRIDES_PATH, 'utf-8');
    const parsed = OverridesSchema.parse(JSON.parse(raw));
    cache = { data: parsed, loadedAt: now };
    return parsed;
  } catch (err) {
    // Fail closed but don't crash the whole pipeline: an unreadable/invalid
    // overrides file should not block publishing, but it should be loud
    // in the job's logged output.
    console.error('[overrides] Failed to load config/overrides.json, using empty overrides:', err);
    const empty = OverridesSchema.parse({});
    cache = { data: empty, loadedAt: now };
    return empty;
  }
}

export async function isExcluded(slug: string): Promise<boolean> {
  const { excludedSlugs } = await loadOverrides();
  return excludedSlugs.includes(slug);
}

export async function getPinnedFacts(slug: string) {
  const { pinnedFacts } = await loadOverrides();
  return pinnedFacts[slug] ?? null;
}

export async function getFeaturedSlugs(): Promise<string[]> {
  const { featuredSlugs } = await loadOverrides();
  return featuredSlugs;
}

export async function getForceRegenerateSlugs(): Promise<string[]> {
  const { forceRegenerate } = await loadOverrides();
  return forceRegenerate;
}
