// NERF Context Store — Query Layer & Formatters
//
// Typed query functions for decisions and requirements from the DB views,
// with optional filtering. Format functions produce prompt-injectable markdown.
// All functions degrade gracefully: return empty results when DB unavailable, never throw.
import { isDbAvailable, _getAdapter } from './nerf-db.js';
/**
 * Query active (non-superseded) decisions with optional filters.
 * - milestoneId: filters where when_context LIKE '%milestoneId%'
 * - scope: filters where scope = :scope (exact match)
 *
 * Returns [] if DB is not available. Never throws.
 */
export function queryDecisions(opts) {
    if (!isDbAvailable())
        return [];
    const adapter = _getAdapter();
    if (!adapter)
        return [];
    try {
        const clauses = ['superseded_by IS NULL'];
        const params = {};
        if (opts?.milestoneId) {
            // D3: equality first, then prefix-only LIKE — avoids leading-wildcard full-table scan
            clauses.push('(when_context = :milestone_id OR when_context LIKE :milestone_prefix)');
            params[':milestone_id'] = opts.milestoneId;
            params[':milestone_prefix'] = `${opts.milestoneId}%`;
        }
        if (opts?.scope) {
            clauses.push('scope = :scope');
            params[':scope'] = opts.scope;
        }
        const sql = `SELECT * FROM decisions WHERE ${clauses.join(' AND ')} ORDER BY seq`;
        const rows = adapter.prepare(sql).all(params);
        return rows.map(row => ({
            seq: row['seq'],
            id: row['id'],
            when_context: row['when_context'],
            scope: row['scope'],
            decision: row['decision'],
            choice: row['choice'],
            rationale: row['rationale'],
            revisable: row['revisable'],
            made_by: row['made_by'] ?? 'agent',
            superseded_by: null,
        }));
    }
    catch {
        return [];
    }
}
/**
 * Query active (non-superseded) requirements with optional filters.
 * - sliceId: filters where primary_owner LIKE '%sliceId%' OR supporting_slices LIKE '%sliceId%'
 * - status: filters where status = :status (exact match)
 *
 * Returns [] if DB is not available. Never throws.
 */
export function queryRequirements(opts) {
    if (!isDbAvailable())
        return [];
    const adapter = _getAdapter();
    if (!adapter)
        return [];
    try {
        const clauses = ['superseded_by IS NULL'];
        const params = {};
        if (opts?.sliceId) {
            // D3: exact match for primary_owner; LIKE only for supporting_slices (comma-delimited)
            clauses.push('(primary_owner = :slice_id OR supporting_slices LIKE :slice_pattern)');
            params[':slice_id'] = opts.sliceId;
            params[':slice_pattern'] = `%${opts.sliceId}%`;
        }
        if (opts?.status) {
            clauses.push('status = :status');
            params[':status'] = opts.status;
        }
        const sql = `SELECT * FROM requirements WHERE ${clauses.join(' AND ')} ORDER BY id`;
        const rows = adapter.prepare(sql).all(params);
        return rows.map(row => ({
            id: row['id'],
            class: row['class'],
            status: row['status'],
            description: row['description'],
            why: row['why'],
            source: row['source'],
            primary_owner: row['primary_owner'],
            supporting_slices: row['supporting_slices'],
            validation: row['validation'],
            notes: row['notes'],
            full_content: row['full_content'],
            superseded_by: null,
        }));
    }
    catch {
        return [];
    }
}
// ─── Format Functions ──────────────────────────────────────────────────────
/**
 * Format decisions as a markdown table matching DECISIONS.md format.
 * Returns empty string for empty input.
 */
export function formatDecisionsForPrompt(decisions) {
    if (decisions.length === 0)
        return '';
    const header = '| # | When | Scope | Decision | Choice | Rationale | Revisable? | Made By |';
    const separator = '|---|------|-------|----------|--------|-----------|------------|---------|';
    const rows = decisions.map(d => `| ${d.id} | ${d.when_context} | ${d.scope} | ${d.decision} | ${d.choice} | ${d.rationale} | ${d.revisable} | ${d.made_by ?? 'agent'} |`);
    return [header, separator, ...rows].join('\n');
}
/**
 * Format requirements as structured H3 sections matching REQUIREMENTS.md format.
 * Returns empty string for empty input.
 */
export function formatRequirementsForPrompt(requirements) {
    if (requirements.length === 0)
        return '';
    return requirements.map(r => {
        const lines = [
            `### ${r.id}: ${r.description}`,
            '',
            `- **Class:** ${r.class}`,
            `- **Status:** ${r.status}`,
            `- **Why:** ${r.why}`,
            `- **Source:** ${r.source}`,
            `- **Primary Owner:** ${r.primary_owner}`,
        ];
        if (r.supporting_slices) {
            lines.push(`- **Supporting Slices:** ${r.supporting_slices}`);
        }
        lines.push(`- **Validation:** ${r.validation}`);
        if (r.notes) {
            lines.push(`- **Notes:** ${r.notes}`);
        }
        return lines.join('\n');
    }).join('\n\n');
}
// ─── Artifact Query Functions ──────────────────────────────────────────────
/**
 * Query a hierarchy artifact by its relative path.
 * Returns the full_content string or null if not found/unavailable.
 * Never throws.
 */
export function queryArtifact(path) {
    if (!isDbAvailable())
        return null;
    const adapter = _getAdapter();
    if (!adapter)
        return null;
    try {
        const row = adapter.prepare('SELECT full_content FROM artifacts WHERE path = :path').get({ ':path': path });
        if (!row)
            return null;
        const content = row['full_content'];
        return content || null;
    }
    catch {
        return null;
    }
}
/**
 * Query PROJECT.md content from the artifacts table.
 * PROJECT.md is stored with the relative path 'PROJECT.md' by the importer.
 * Returns the content string or null if not found/unavailable.
 * Never throws.
 */
export function queryProject() {
    return queryArtifact('PROJECT.md');
}
