// tools/manage-context/note-health-handlers.ts — cleanup, add-note, get-context, doc-health handlers
import { readFile, writeFile, mkdir } from 'node:fs/promises';
import { join } from 'node:path';
import { generateDocHealthReport } from '../../engine/context/index.js';
import { notesDir, sanitizeKey, readMeta, deleteNote, listNoteKeys, listNoteFilenames, isExpired, preview, getMinPriority, generateFrontmatter, parseFrontmatter, } from './store.js';
import { compactJson } from '../output-formatter.js';
const SEVEN_DAYS_MS = 7 * 24 * 60 * 60 * 1000;
const NINETY_DAYS_MS = 90 * 24 * 60 * 60 * 1000;
export async function handleCleanup(projectId) {
    // 1. Clean expired context/ notes (existing behavior)
    const keys = await listNoteKeys(projectId);
    let removedCount = 0;
    const removedKeys = [];
    for (const safeKey of keys) {
        const meta = await readMeta(projectId, safeKey);
        if (meta && isExpired(meta)) {
            await deleteNote(projectId, safeKey);
            removedCount++;
            removedKeys.push(meta.key);
        }
    }
    // 2. Generate DocHealthReport from notes/ directory
    const noteFiles = await listNoteFilenames(projectId);
    const dir = notesDir(projectId);
    const archivable = [];
    const orphans = [];
    const outdated = [];
    const now = Date.now();
    for (const filename of noteFiles) {
        const filepath = join(dir, filename);
        let raw;
        try {
            raw = await readFile(filepath, 'utf-8');
        }
        catch {
            continue;
        }
        const fm = parseFrontmatter(raw);
        const createdAt = fm?.createdAt ? new Date(fm.createdAt).getTime() : 0;
        const resolvedAt = fm?.resolvedAt ? new Date(fm.resolvedAt).getTime() : 0;
        const hasSpecId = Boolean(fm?.specId);
        const isPendingTag = (fm?.tags ?? []).includes('pending');
        // Archivable: resolved (has resolvedAt) and resolved > 7 days ago
        if (resolvedAt > 0 && now - resolvedAt > SEVEN_DAYS_MS) {
            archivable.push(filename);
        }
        // Orphan: no specId linked
        if (!hasSpecId && !isPendingTag) {
            orphans.push(filename);
        }
        // Outdated: older than 90 days with no resolution
        if (createdAt > 0 && now - createdAt > NINETY_DAYS_MS && resolvedAt === 0) {
            outdated.push(filename);
        }
    }
    const totalIssues = archivable.length + orphans.length + outdated.length;
    const total = noteFiles.length;
    const score = total === 0 ? 100 : Math.max(0, Math.round(((total - totalIssues) / total) * 100));
    const docHealthReport = {
        archivable,
        orphans,
        outdated,
        score,
        summary: `${total} note(s) found. ${archivable.length} archivable, ${orphans.length} orphan(s), ${outdated.length} outdated. Health score: ${score}/100.`,
        totalNotes: total,
        totalSpecs: 0,
        generatedAt: new Date().toISOString(),
    };
    const result = {
        action: 'cleanup',
        notes: removedKeys.map((k) => ({
            key: k,
            createdAt: '',
            preview: '(expired — removed)',
        })),
        docHealthReport,
        message: `Cleanup complete: removed ${removedCount} expired note(s). Health score: ${score}/100.`,
    };
    return {
        content: [{ type: 'text', text: compactJson(result) }],
    };
}
export async function handleAddNote(projectId, key, content, tags, specId) {
    const dir = notesDir(projectId);
    await mkdir(dir, { recursive: true });
    const now = new Date().toISOString();
    const safeKey = sanitizeKey(key);
    const frontmatter = generateFrontmatter(tags, specId, now);
    const fullContent = `${frontmatter}\n\n${content}`;
    const filepath = join(dir, `${safeKey}.md`);
    await writeFile(filepath, fullContent, 'utf-8');
    const result = {
        action: 'add-note',
        key,
        message: `Note '${key}' created with tags [${tags.join(', ')}]${specId ? ` linked to ${specId}` : ''}.`,
    };
    return {
        content: [{ type: 'text', text: compactJson(result) }],
    };
}
export async function handleGetContext(projectId) {
    const dir = notesDir(projectId);
    const noteFiles = await listNoteFilenames(projectId);
    const enrichedNotes = [];
    for (const filename of noteFiles) {
        const filepath = join(dir, filename);
        let raw;
        try {
            raw = await readFile(filepath, 'utf-8');
        }
        catch {
            continue;
        }
        const fm = parseFrontmatter(raw);
        const bodyStart = raw.indexOf('\n---', 3);
        const body = bodyStart !== -1 ? raw.slice(bodyStart + 4).trim() : raw;
        const notePreview = preview(body);
        const createdAt = fm?.createdAt ?? 'unknown';
        // Skip notes resolved more than 7 days ago
        if (fm?.resolvedAt) {
            const resolvedMs = new Date(fm.resolvedAt).getTime();
            if (Date.now() - resolvedMs > SEVEN_DAYS_MS) {
                continue;
            }
        }
        enrichedNotes.push({
            key: filename.replace(/\.md$/, ''),
            createdAt,
            preview: notePreview,
            tags: fm?.tags ?? [],
            specId: fm?.specId,
        });
    }
    // Sort: by tag priority first, then by recency
    enrichedNotes.sort((a, b) => {
        /* v8 ignore next 2 */
        const pa = getMinPriority(a.tags ?? []);
        const pb = getMinPriority(b.tags ?? []);
        if (pa !== pb) {
            return pa - pb;
        }
        if (a.createdAt === 'unknown') {
            return 1;
        }
        if (b.createdAt === 'unknown') {
            return -1;
        }
        return b.createdAt.localeCompare(a.createdAt);
    });
    /* v8 ignore next 2 */
    const blockers = enrichedNotes.filter((n) => n.tags?.includes('blocker') ?? false);
    const pending = enrichedNotes.filter((n) => n.tags?.includes('pending') ?? false);
    let summaryMsg = `Found ${enrichedNotes.length} active note(s).`;
    if (blockers.length > 0) {
        summaryMsg += ` ${blockers.length} blocker(s) need immediate attention.`;
    }
    if (pending.length > 0) {
        summaryMsg += ` ${pending.length} pending item(s).`;
    }
    const result = {
        action: 'get-context',
        notes: enrichedNotes,
        message: summaryMsg,
    };
    return {
        content: [{ type: 'text', text: compactJson(result) }],
    };
}
export async function handleDocHealth(projectId) {
    // Collect notes from context/ dir
    const keys = await listNoteKeys(projectId);
    const noteInfos = [];
    for (const safeKey of keys) {
        const meta = await readMeta(projectId, safeKey);
        if (!meta || isExpired(meta)) {
            continue;
        }
        noteInfos.push({
            key: meta.key,
            specId: meta.specId,
            tags: meta.tags,
            createdAt: meta.createdAt,
        });
    }
    // Also collect from notes/ dir (tagged notes)
    const noteFiles = await listNoteFilenames(projectId);
    const nDir = notesDir(projectId);
    for (const filename of noteFiles) {
        try {
            const raw = await readFile(join(nDir, filename), 'utf-8');
            const fm = parseFrontmatter(raw);
            noteInfos.push({
                key: filename.replace(/\.md$/, ''),
                specId: fm?.specId,
                tags: fm?.tags ?? [],
                createdAt: fm?.createdAt ?? '',
            });
        }
        catch {
            /* ignore */
        }
    }
    const report = generateDocHealthReport(noteInfos, []);
    const result = {
        action: 'doc-health',
        docHealthReport: report,
        message: `Doc health: score ${report.score}/100. ${report.summary} (Never auto-deletes.)`,
    };
    return { content: [{ type: 'text', text: compactJson(result) }] };
}
//# sourceMappingURL=note-health-handlers.js.map