#!/usr/bin/env npx tsx
/**
 * Research Index Automation Script
 *
 * Regenerates RESEARCH_INDEX.md from YAML registry files (papers.yaml, techniques.yaml).
 *
 * Usage:
 *   npx tsx scripts/update-research-index.ts            # Regenerate index
 *   npx tsx scripts/update-research-index.ts --check     # Check if index is up to date (CI)
 *   npx tsx scripts/update-research-index.ts --validate  # Validate registry consistency
 *
 * (Source: Issue #632 - Research Index Automation)
 */

/* eslint-disable no-console */

import { writeFileSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import {
  type PaperEntry,
  type TechniqueEntry,
  TOPIC_META,
  ALL_TOPICS,
  loadPapers,
  loadTechniques,
  getETDate,
  checkFreshness,
  validateRegistry,
  computeTopicStats,
} from './research-index-helpers.js';
import { ROOT } from './script-paths.js';
const REGISTRY_DIR = join(ROOT, 'docs/research/registry');
const PAPERS_PATH = join(REGISTRY_DIR, 'papers.yaml');
const TECHNIQUES_PATH = join(REGISTRY_DIR, 'techniques.yaml');
const INDEX_PATH = join(ROOT, 'docs/research/RESEARCH_INDEX.md');

// ============================================================================
// Section Generators
// ============================================================================

function generateFrontmatter(papersChecksum: string, techniquesChecksum: string): string {
  return [
    '<!--',
    '  Auto-generated by scripts/update-research-index.ts',
    '  DO NOT EDIT MANUALLY - changes will be overwritten',
    `  papers: sha256:${papersChecksum}`,
    `  techniques: sha256:${techniquesChecksum}`,
    '-->',
  ].join('\n');
}

function generateHeader(dateStr: string, totalPapers: number, totalTechniques: number): string {
  return [
    '# Nexus-Agents Research Index',
    '',
    `**Generated:** ${dateStr} (ET)`,
    `**Total Papers:** ${String(totalPapers)} | **Techniques:** ${String(totalTechniques)} | **Topics:** ${String(ALL_TOPICS.length)}`,
  ].join('\n');
}

function generateQuickStats(techniques: Record<string, TechniqueEntry>): string {
  const counts: Record<string, number> = {};
  for (const tech of Object.values(techniques)) {
    counts[tech.status] = (counts[tech.status] ?? 0) + 1;
  }
  return [
    '---',
    '',
    '## Quick Stats',
    '',
    '| Status      | Papers | Techniques |',
    '| ----------- | ------ | ---------- |',
    `| Implemented | -      | ${String(counts['implemented'] ?? 0)}         |`,
    `| In Progress | -      | ${String(counts['in-progress'] ?? 0)}          |`,
    `| Planned     | -      | ${String(counts['planned'] ?? 0)}          |`,
    `| Not Started | -      | ${String(counts['not-started'] ?? 0)}          |`,
    `| Rejected    | -      | ${String(counts['rejected'] ?? 0)}          |`,
    '',
    '> **Note:** Paper-level status tracking deprecated. Technique status is source of truth.',
  ].join('\n');
}

function generateTopicsTable(
  papers: Record<string, PaperEntry>,
  techniques: Record<string, TechniqueEntry>
): string {
  const stats = computeTopicStats(papers, techniques);
  return [
    '---',
    '',
    '## Topics',
    '',
    '| Topic                                               | Papers | Techniques | Description                          |',
    '| --------------------------------------------------- | ------ | ---------- | ------------------------------------ |',
    ...stats.map((ts) => {
      const meta = TOPIC_META[ts.topic];
      const display = meta?.display ?? ts.topic;
      const desc = meta?.description ?? '';
      return `| [${display}](topics/${ts.topic}/README.md) | ${String(ts.papers)} | ${String(ts.techniques)} | ${desc} |`;
    }),
  ].join('\n');
}

function formatTechniqueRow(t: TechniqueEntry & { id: string }): string {
  const metricsStr =
    t.metrics !== undefined
      ? Object.entries(t.metrics)
          .map(([k, v]) => `${k}: ${v}`)
          .join(', ')
      : '-';
  const issue =
    t.implementation_issue !== undefined && t.implementation_issue !== null
      ? `#${String(t.implementation_issue)}`
      : '-';
  return `| [${t.name}](registry/techniques.yaml#${t.id}) | ${t.topic} | ${metricsStr} | ${issue} |`;
}

function generatePrioritySection(
  techniques: Record<string, TechniqueEntry>,
  priority: string,
  heading: string,
  description: string,
  tableHeader: string
): string | null {
  const filtered = Object.entries(techniques)
    .filter(([, t]) => t.priority === priority)
    .map(([id, t]) => ({ id, ...t }));
  if (filtered.length === 0) {
    return null;
  }
  return [
    '---',
    '',
    `## ${heading}`,
    '',
    description,
    '',
    tableHeader,
    ...filtered.map(formatTechniqueRow),
  ].join('\n');
}

function generateRecentPapers(papers: Record<string, PaperEntry>): string | null {
  const recent = Object.entries(papers)
    .filter(([, p]) => p.reviewed_date !== undefined && p.reviewed_date !== '')
    .sort(([, a], [, b]) => (b.reviewed_date ?? '').localeCompare(a.reviewed_date ?? ''))
    .slice(0, 5);
  if (recent.length === 0) {
    return null;
  }
  const rows = recent.map(([, p]) => {
    const topic = p.topics[0] ?? '-';
    return `| ${p.reviewed_date ?? '-'} | [${p.title}](${p.url}) | ${topic} | - |`;
  });
  return [
    '---',
    '',
    '## Recently Reviewed Papers',
    '',
    '| Date       | Paper                                                                                                    | Topic           | Priority |',
    '| ---------- | -------------------------------------------------------------------------------------------------------- | --------------- | -------- |',
    ...rows,
  ].join('\n');
}

function generatePapersByTopic(papers: Record<string, PaperEntry>): string {
  const sections = ['---', '', '## Papers by Topic'];
  for (const topic of ALL_TOPICS) {
    const topicPapers = Object.entries(papers).filter(([, p]) => p.topics.includes(topic));
    if (topicPapers.length === 0) {
      continue;
    }
    const meta = TOPIC_META[topic];
    const display = meta?.display ?? topic;
    const lines = topicPapers.map(([, p]) => {
      const raw = p.summary !== undefined ? (p.summary.trim().split('\n')[0] ?? '') : '';
      const summary = raw.length > 80 ? raw.slice(0, 77) + '...' : raw;
      return `- [${p.title}](${p.url}) - ${summary}`;
    });
    sections.push('', `### ${display} (${String(topicPapers.length)} papers)`, '', ...lines);
  }
  return sections.join('\n');
}

function generateGitHubIssues(techniques: Record<string, TechniqueEntry>): string | null {
  const withIssues = Object.entries(techniques)
    .filter(([, t]) => t.implementation_issue !== undefined && t.implementation_issue !== null)
    .map(([, t]) => t);
  if (withIssues.length === 0) {
    return null;
  }
  const rows = withIssues.map((t) => {
    const issue = `#${String(t.implementation_issue)}`;
    const related = (t.source_papers ?? []).join(', ');
    return `| ${issue} | ${t.name} | ${related} |`;
  });
  return [
    '',
    '---',
    '',
    '## GitHub Issues',
    '',
    '| Issue | Feature                                    | Related Papers                     |',
    '| ----- | ------------------------------------------ | ---------------------------------- |',
    ...rows,
  ].join('\n');
}

function generateSearchTags(techniques: Record<string, TechniqueEntry>): string {
  const allTags = new Set<string>();
  for (const tech of Object.values(techniques)) {
    if (tech.tags !== undefined) {
      for (const tag of tech.tags) {
        allTags.add(tag);
      }
    }
  }
  const tagStr = [...allTags]
    .sort()
    .map((t) => `\`#${t}\``)
    .join(' ');
  return ['', '---', '', '## Search Tags', '', tagStr].join('\n');
}

function generateFooter(dateStr: string, totalPapers: number, totalTechniques: number): string {
  return [
    '',
    '---',
    '',
    '## Registry Files',
    '',
    `- [papers.yaml](registry/papers.yaml) - All ${String(totalPapers)} papers with metadata`,
    `- [techniques.yaml](registry/techniques.yaml) - All ${String(totalTechniques)} techniques with status`,
    '- [sources.yaml](registry/sources.yaml) - Product docs and other sources',
    '',
    '---',
    '',
    '## How to Contribute',
    '',
    'See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on adding new research.',
    '',
    '---',
    '',
    `_Generated from YAML registries. Last updated: ${dateStr} (ET)_`,
    '',
  ].join('\n');
}

// ============================================================================
// Generate Mode
// ============================================================================

function generateIndex(): string {
  const { registry: papers, checksum: pCS } = loadPapers(PAPERS_PATH);
  const { registry: techniques, checksum: tCS } = loadTechniques(TECHNIQUES_PATH);
  const dateStr = getETDate();
  const totalP = Object.keys(papers.papers).length;
  const totalT = Object.keys(techniques.techniques).length;

  const p1Header =
    '| Technique                                                                                         | Topic           | Key Metrics                                                                                                                           | Issue |\n| ------------------------------------------------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ----- |';
  const p2Header =
    '| Technique                                                                                       | Topic           | Key Metrics                                                                                            | Issue |\n| ----------------------------------------------------------------------------------------------- | --------------- | ------------------------------------------------------------------------------------------------------ | ----- |';

  const sections: string[] = [
    generateFrontmatter(pCS, tCS),
    generateHeader(dateStr, totalP, totalT),
    generateQuickStats(techniques.techniques),
    generateTopicsTable(papers.papers, techniques.techniques),
  ];

  const p1 = generatePrioritySection(
    techniques.techniques,
    'P1',
    'Priority 1 (P1) Techniques',
    'These techniques are high-impact and align well with the current architecture.',
    p1Header
  );
  if (p1 !== null) {
    sections.push(p1);
  }

  const p2 = generatePrioritySection(
    techniques.techniques,
    'P2',
    'Priority 2 (P2) Techniques',
    'Medium-impact or requiring moderate changes.',
    p2Header
  );
  if (p2 !== null) {
    sections.push(p2);
  }

  const recent = generateRecentPapers(papers.papers);
  if (recent !== null) {
    sections.push(recent);
  }

  sections.push(generatePapersByTopic(papers.papers));

  const issues = generateGitHubIssues(techniques.techniques);
  if (issues !== null) {
    sections.push(issues);
  }

  sections.push(generateSearchTags(techniques.techniques));
  sections.push(generateFooter(dateStr, totalP, totalT));
  return sections.join('\n');
}

// ============================================================================
// CLI
// ============================================================================

function printHelp(): void {
  console.log(`
update-research-index.ts - Automate RESEARCH_INDEX.md generation

Usage:
  npx tsx scripts/update-research-index.ts [options]

Options:
  --check       Check if index is up to date (exit 1 if stale)
  --validate    Validate registry cross-references
  --help, -h    Show this help message

(Source: Issue #632 - Research Index Automation)
`);
}

function verifyRegistryFiles(): boolean {
  if (!existsSync(PAPERS_PATH)) {
    console.error(`Error: papers.yaml not found at ${PAPERS_PATH}`);
    return false;
  }
  if (!existsSync(TECHNIQUES_PATH)) {
    console.error(`Error: techniques.yaml not found at ${TECHNIQUES_PATH}`);
    return false;
  }
  return true;
}

function runGenerate(): void {
  console.log('Research Index Generator');
  console.log('=======================\n');
  try {
    const content = generateIndex();
    writeFileSync(INDEX_PATH, content);
    const paperCount = content.match(/Total Papers:\*\* (\d+)/)?.[1] ?? '?';
    const techCount = content.match(/Techniques:\*\* (\d+)/)?.[1] ?? '?';
    console.log(`Generated: ${INDEX_PATH}`);
    console.log(`Papers: ${paperCount}`);
    console.log(`Techniques: ${techCount}`);
    console.log('\nResearch index updated successfully.');
  } catch (error: unknown) {
    const msg = error instanceof Error ? error.message : String(error);
    console.error('Error generating research index:', msg);
    process.exit(1);
  }
}

function main(): void {
  const args = process.argv.slice(2);

  if (args.includes('--help') || args.includes('-h')) {
    printHelp();
    process.exit(0);
  }

  if (!verifyRegistryFiles()) {
    process.exit(1);
  }

  if (args.includes('--check')) {
    process.exit(checkFreshness(INDEX_PATH, PAPERS_PATH, TECHNIQUES_PATH) ? 0 : 1);
  }

  if (args.includes('--validate')) {
    process.exit(validateRegistry(PAPERS_PATH, TECHNIQUES_PATH) ? 0 : 1);
  }

  runGenerate();
}

main();
