import { Hono } from 'hono';
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
import matter from 'gray-matter';
import { marked } from 'marked';
import { safeRel } from '../files.js';

// ÖFFENTLICH: Versionsverlauf eines Library-Beitrags aus der Git-History.
// Der Container hat das Repo unter /site gemountet + git installiert. Wir
// holen alte Fassungen on-demand (kein Vorbauen) und zeigen sie auf der Site.
const execFileP = promisify(execFile);
const SITE_DIR = process.env.SITE_DIR || '/site';
const git = (...args) => execFileP('git', ['-C', SITE_DIR, ...args], { maxBuffer: 10 * 1024 * 1024 });
const US = '\x1f'; // Feldtrenner (Unit Separator) — kommt in Commit-Daten nicht vor.

const history = new Hono();

// Liste der Versionen: neueste zuerst.
history.get('/', async (c) => {
  let rel;
  try { rel = safeRel(c.req.query('path')); } catch { return c.json({ error: 'Ungültiger Pfad' }, 400); }
  try {
    const { stdout } = await git(
      'log', '--follow', `--format=%H${US}%h${US}%aI${US}%an${US}%s`, '--', `content/${rel}`);
    const versions = stdout.trim().split('\n').filter(Boolean).map((line) => {
      const [rev, short, date, author, subject] = line.split(US);
      return { rev, short, date, author, subject };
    });
    return c.json(versions);
  } catch { return c.json({ error: 'Verlauf nicht verfügbar' }, 500); }
});

// Eine bestimmte Fassung gerendert (HTML), zum Anzeigen auf der Seite.
history.get('/version', async (c) => {
  let rel;
  try { rel = safeRel(c.req.query('path')); } catch { return c.json({ error: 'Ungültiger Pfad' }, 400); }
  const rev = c.req.query('rev') || '';
  if (!/^[0-9a-f]{7,40}$/i.test(rev)) return c.json({ error: 'Ungültige Version' }, 400);
  try {
    const { stdout } = await git('show', `${rev}:content/${rel}`);
    const { data, content } = matter(stdout);
    return c.json({
      rev,
      title: data.title || '',
      date: data.date ? new Date(data.date).toISOString().slice(0, 10) : null,
      html: renderMarkdown(content),
    });
  } catch { return c.json({ error: 'Version nicht gefunden' }, 404); }
});

// Unified-Diff einer Fassung (was dieser Commit an der Datei geändert hat) —
// fürs rot/grün-Diff auf der Seite. Roh-Diff; das Frontend färbt +/- ein.
history.get('/diff', async (c) => {
  let rel;
  try { rel = safeRel(c.req.query('path')); } catch { return c.json({ error: 'Ungültiger Pfad' }, 400); }
  const rev = c.req.query('rev') || '';
  if (!/^[0-9a-f]{7,40}$/i.test(rev)) return c.json({ error: 'Ungültige Version' }, 400);
  try {
    const { stdout } = await git('show', '--format=', '--no-color', rev, '--', `content/${rel}`);
    return c.json({ rev, diff: stdout });
  } catch { return c.json({ error: 'Diff nicht verfügbar' }, 404); }
});

// Markdown → HTML. marked kennt Goldmarks Fußnoten ([^id]) nicht — daher
// vorab: Definitionen einsammeln, Verweise zu <sup>-Nummern, „Quellen" anhängen
// (greift dieselbe .footnotes-CSS wie die Live-Seite).
function renderMarkdown(md) {
  const defs = {}; const order = [];
  md = md.replace(/^\[\^([^\]]+)\]:[ \t]*(.*)$/gm, (_, id, txt) => { defs[id] = txt; return ''; });
  md = md.replace(/\[\^([^\]]+)\]/g, (_, id) => {
    if (!order.includes(id)) order.push(id);
    return `<sup class="footnote-ref">${order.indexOf(id) + 1}</sup>`;
  });
  let html = marked.parse(md);
  if (order.length) {
    html += '<div class="footnotes"><ol>'
      + order.map((id) => `<li>${marked.parseInline(defs[id] || '')}</li>`).join('')
      + '</ol></div>';
  }
  return html;
}

export default history;
