#!/usr/bin/env node
/**
 * @agent-manifest
 * name:        research
 * title:       Editorial Calendar Researcher
 * class:       content
 * trigger:     manual (auto-invoked by writer when the evergreen backlog runs low)
 * description: Top up the evergreen backlog in calendar.json (additive, deduped); timely news is the news radar's job.
 * model:       research=claude-opus-4-8
 * prompt:      prompts/research.system.md
 * skills:      -
 * tools:       lib/claude.mjs, lib/calendar.mjs
 * reads:       -
 * writes:      -
 * created:     2026-07-04
 * @end
 */
// Editorial research: top up the EVERGREEN backlog in calendar.json (additive, deduped).
// Timely news is handled separately by the news radar. Usage:
//   node agents/scripts/research.mjs [count]
import { readdirSync, existsSync } from "node:fs";
import { dirname, resolve, join } from "node:path";
import { fileURLToPath } from "node:url";
import { runClaude } from "./lib/claude.mjs";
import { loadJson, todayInTz, addDays } from "./lib/util.mjs";
import { readCalendar, mergeEntries } from "./lib/calendar.mjs";

const HERE = dirname(fileURLToPath(import.meta.url));
const PIPELINE = resolve(HERE, "..");
const cfg = loadJson(join(PIPELINE, "config.json"));
const root = cfg.paths.projectRoot;

const publishedSlugs = () => {
  const d = join(root, cfg.paths.blogContentDir);
  return existsSync(d)
    ? readdirSync(d, { withFileTypes: true }).filter((x) => x.isDirectory()).map((x) => x.name)
    : [];
};

/** Scan for evergreen topics and additively merge them into calendar.json. Returns count added. */
export async function runResearch({ count } = {}) {
  const n = count || cfg.editorial.calendarDays;
  const today = todayInTz(cfg.editorial.timezone);
  const calendarPath = join(root, cfg.paths.calendar);
  const scanPath = join(root, "agents", "research-scan.json");

  // Per-type target counts from the configured mix.
  const types = Object.keys(cfg.editorial.contentMix);
  const counts = {};
  let assigned = 0;
  for (const t of types) {
    counts[t] = Math.round(cfg.editorial.contentMix[t] * n);
    assigned += counts[t];
  }
  const biggest = types.reduce((a, b) => (counts[a] >= counts[b] ? a : b));
  counts[biggest] += n - assigned;

  const exclude = [...new Set([...readCalendar(calendarPath).map((e) => e.slug), ...publishedSlugs()])];

  const prompt = `Propose ${n} evergreen Comiida topics.

- Write a JSON array of ${n} topic proposals to: ${scanPath}
- Do NOT assign dates (the pipeline schedules them).
- Allowed content types: ${types.join(", ")}
- Rough target counts per type: ${JSON.stringify(counts)}
- DO NOT reuse any of these slugs: ${exclude.join(", ") || "(none yet)"}
- Read existing posts if useful: ${join(root, cfg.paths.blogContentDir)}

Follow the output contract in your system prompt exactly.`;

  console.log(`[research] proposing ${n} evergreen topics, mix ${JSON.stringify(counts)}`);

  await runClaude({
    prompt,
    systemPromptFile: join(PIPELINE, "prompts/research.system.md"),
    model: cfg.models.research,
    allowedTools: "Read Glob Grep WebSearch Write",
    addDirs: [root],
    cwd: root,
    logFile: join(root, cfg.paths.logsDir, `research-${today}.log`),
  });

  const proposals = existsSync(scanPath) ? loadJson(scanPath) : [];
  if (!proposals.length) {
    console.log("[research] no proposals produced.");
    return 0;
  }

  // Schedule new topics one per day, starting the day after the latest existing date.
  const dates = readCalendar(calendarPath).map((e) => (e.date || "").slice(0, 10)).filter(Boolean);
  const maxDate = dates.sort().pop();
  let next = maxDate && maxDate >= today ? addDays(maxDate, 1) : today;

  const entries = proposals.map((p) => {
    const entry = { ...p, date: next, status: "planned" };
    next = addDays(next, 1);
    return entry;
  });

  const added = await mergeEntries(calendarPath, entries);
  const planned = readCalendar(calendarPath).filter((e) => e.status === "planned").length;
  console.log(`[research] added ${added} evergreen topics. Planned backlog now: ${planned}.`);
  return added;
}

// CLI
if (import.meta.url === `file://${process.argv[1]}`) {
  const count = parseInt(process.argv[2], 10) || undefined;
  await runResearch({ count });
}
