// engine/spec-changelog/core.ts — Changelog entry creation and persistence
import { readFile, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
const CHANGELOG_FILENAME = 'CHANGELOG.md';
const CHANGELOG_VERSION_COMMENT = '<!-- changelog-version: 1 -->';
/** Format a single changelog entry as Markdown. */
export function formatEntry(entry, specId) {
    const lines = [];
    lines.push(`## ${entry.timestamp} — ${entry.type}`);
    lines.push('');
    lines.push(`**Tool**: ${entry.triggeredBy}`);
    lines.push(`**Descripcion**: ${entry.description}`);
    lines.push('');
    if (entry.before !== undefined && entry.after !== undefined) {
        if (entry.type === 'status_changed') {
            lines.push(`**Antes**: ${entry.before.status} | **Despues**: ${entry.after.status}`);
            lines.push(`**Progreso**: ${entry.before.completedCount}/${entry.before.criteriaCount} → ${entry.after.completedCount}/${entry.after.criteriaCount}`);
        }
        else {
            lines.push(`**Criterios antes**: ${entry.before.criteriaCount} | **Criterios despues**: ${entry.after.criteriaCount}`);
            if (entry.type === 'progress_updated') {
                lines.push(`**Progreso**: ${entry.before.completedCount}/${entry.before.criteriaCount} → ${entry.after.completedCount}/${entry.after.criteriaCount}`);
            }
        }
        lines.push('');
    }
    if (entry.diff !== undefined) {
        const { added, removed, modified } = entry.diff;
        const hasCriteriaChanges = added.length > 0 || removed.length > 0 || modified.length > 0;
        if (hasCriteriaChanges) {
            lines.push('### Criterios modificados');
            for (const item of added) {
                lines.push(`\u2795 ${item}`);
            }
            for (const item of removed) {
                lines.push(`\u2796 ${item}`);
            }
            for (const item of modified) {
                lines.push(`\u270f\ufe0f ${item.after} (antes: ${item.before})`);
            }
            lines.push('');
        }
    }
    lines.push('---');
    lines.push('');
    void specId; // referenced in header externally
    return lines.join('\n');
}
/** Build the full CHANGELOG.md header for a spec. */
function buildHeader(specId, specTitle) {
    const title = specTitle ? `${specId}: ${specTitle}` : specId;
    return [CHANGELOG_VERSION_COMMENT, '', `# Changelog — ${title}`, '', ''].join('\n');
}
/** Parse the timestamp from the first entry in a CHANGELOG.md content. */
export function parseFirstEntryTimestamp(content) {
    // Matches lines like: ## 2026-03-04T14:23:00Z — reconciled
    const match = /^## (\d{4}-\d{2}-\d{2}T[\d:.]+Z) —/m.exec(content);
    return match?.[1] ?? null;
}
/** Parse changelog entries from a CHANGELOG.md content string. */
export function parseChangelogEntries(content, specId) {
    const entries = [];
    // Split on section headers: ## <timestamp> — <type>
    const sectionRegex = /^## (\d{4}-\d{2}-\d{2}T[\d:.]+Z) — (\w+)/gm;
    const matches = [...content.matchAll(sectionRegex)];
    for (const match of matches) {
        const timestamp = match[1];
        const type = match[2];
        if (timestamp === undefined || type === undefined) {
            continue;
        }
        const sectionStart = match.index;
        const nextMatch = matches[matches.indexOf(match) + 1];
        const sectionEnd = nextMatch?.index ?? content.length;
        const sectionContent = content.slice(sectionStart, sectionEnd);
        // Extract tool name
        const toolMatch = /\*\*Tool\*\*: (.+)/.exec(sectionContent);
        const triggeredBy = toolMatch?.[1]?.trim() ?? 'unknown';
        // Extract description
        const descMatch = /\*\*Descripcion\*\*: (.+)/.exec(sectionContent);
        const description = descMatch?.[1]?.trim() ?? '';
        entries.push({
            timestamp,
            type: type,
            description,
            triggeredBy,
        });
    }
    void specId;
    return entries;
}
/** Read the CHANGELOG.md for a spec directory. Returns null if not found. */
export async function readChangelog(options) {
    const { specDir, specId } = options;
    const filePath = join(specDir, CHANGELOG_FILENAME);
    try {
        const content = await readFile(filePath, 'utf-8');
        const entries = parseChangelogEntries(content, specId);
        return { specId, entries };
    }
    catch {
        return null;
    }
}
/** Read only the timestamp of the last (most recent) changelog entry. Optimized for list_specs. */
export async function readLastModifiedTimestamp(specDir) {
    const filePath = join(specDir, CHANGELOG_FILENAME);
    try {
        const content = await readFile(filePath, 'utf-8');
        return parseFirstEntryTimestamp(content);
    }
    catch {
        return null;
    }
}
/** Append a new entry to the CHANGELOG.md for a spec. Creates the file if it doesn't exist. */
export async function appendChangelogEntry(options) {
    const { specDir, specId, entry } = options;
    const filePath = join(specDir, CHANGELOG_FILENAME);
    try {
        let existingContent = '';
        let hasHeader = false;
        try {
            existingContent = await readFile(filePath, 'utf-8');
            hasHeader = existingContent.includes(CHANGELOG_VERSION_COMMENT);
        }
        catch {
            // File doesn't exist yet — will create fresh
        }
        const entryMarkdown = formatEntry(entry, specId);
        let newContent;
        if (!hasHeader) {
            newContent = buildHeader(specId) + entryMarkdown + existingContent;
        }
        else {
            // Insert after the header block (after the # Changelog line)
            const insertAfterPattern = /^# Changelog[^\n]*\n\n/m;
            const match = insertAfterPattern.exec(existingContent);
            if (match) {
                const insertAt = match.index + match[0].length;
                newContent =
                    existingContent.slice(0, insertAt) + entryMarkdown + existingContent.slice(insertAt);
            }
            else {
                // Fallback: append after existing content
                newContent = existingContent + entryMarkdown;
            }
        }
        await writeFile(filePath, newContent, 'utf-8');
        return true;
    }
    catch (error) {
        console.error(`[spec-changelog] Failed to write CHANGELOG.md for ${specId}:`, error);
        return false;
    }
}
/** Format a relative date string (e.g. "hace 2 dias") for a timestamp. */
export function formatRelativeDate(timestamp) {
    const date = new Date(timestamp);
    const now = new Date();
    const diffMs = now.getTime() - date.getTime();
    const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
    if (diffDays === 0) {
        return 'hoy';
    }
    if (diffDays === 1) {
        return 'hace 1 dia';
    }
    if (diffDays <= 30) {
        return `hace ${diffDays} dias`;
    }
    // Older than 30 days: return ISO date portion
    return timestamp.slice(0, 10);
}
//# sourceMappingURL=core.js.map