/** SDK-owned platform module. This implementation is maintained in goodvibes-sdk. */
import { summarizeError } from '../utils/error-display.js';
import { logger } from '../utils/logger.js';
/** Returns true if a Constraint entry is well-formed. */
function isWellFormedConstraint(c) {
    if (typeof c !== 'object' || c === null)
        return false;
    const obj = c;
    return (typeof obj['id'] === 'string' && obj['id'].length > 0 &&
        typeof obj['text'] === 'string' && obj['text'].length > 0 &&
        (obj['source'] === 'prompt' || obj['source'] === 'inherited'));
}
/** Returns true if a ConstraintFinding entry is well-formed. */
function isWellFormedConstraintFinding(f) {
    if (typeof f !== 'object' || f === null)
        return false;
    const obj = f;
    const severity = obj['severity'];
    return (typeof obj['constraintId'] === 'string' && obj['constraintId'].length > 0 &&
        typeof obj['satisfied'] === 'boolean' &&
        typeof obj['evidence'] === 'string' && obj['evidence'].length > 0 &&
        (severity === undefined || severity === 'critical' || severity === 'major' || severity === 'minor'));
}
function filterWellFormed(raw, guard) {
    if (raw === undefined)
        return { items: [], dropped: 0, malformedContainer: false };
    if (!Array.isArray(raw))
        return { items: [], dropped: 0, malformedContainer: true };
    const items = [];
    let dropped = 0;
    for (const item of raw) {
        if (guard(item)) {
            items.push(item);
        }
        else {
            dropped += 1;
        }
    }
    return { items, dropped, malformedContainer: false };
}
function appendEngineerIssue(report, issue) {
    const existing = Array.isArray(report['issues'])
        ? report['issues'].filter((item) => typeof item === 'string')
        : [];
    report['issues'] = [...existing, issue];
}
function appendReviewerIssue(report, description) {
    const existing = Array.isArray(report['issues'])
        ? report['issues'].filter((item) => typeof item === 'object' && item !== null &&
            typeof item.severity === 'string' &&
            typeof item.description === 'string' &&
            typeof item.pointValue === 'number')
        : [];
    report['issues'] = [
        ...existing,
        {
            severity: 'major',
            description,
            pointValue: 2,
        },
    ];
}
export function parseCompletionReport(rawOutput) {
    // Strategy 1: Find ```json ... ``` block
    const jsonBlockMatch = rawOutput.match(/```json\s*\n(\{[\s\S]*?\})\s*\n```/);
    if (jsonBlockMatch) {
        try {
            const parsed = JSON.parse(jsonBlockMatch[1]);
            if (parsed.version === 1 && parsed.archetype)
                return applyConstraintDefaults(parsed);
        }
        catch (error) {
            logger.debug('Completion report fenced JSON parse failed', { error: summarizeError(error) });
        }
    }
    // Strategy 2: Brace-counting extraction — find "version": 1, walk backward for opening {,
    // then forward counting braces to find the matching }. Avoids greedy regex over-matching.
    const versionIdx = rawOutput.indexOf('"version"');
    if (versionIdx !== -1) {
        // Walk backward to find opening brace
        let openBrace = -1;
        for (let i = versionIdx - 1; i >= 0; i--) {
            if (rawOutput[i] === '{') {
                openBrace = i;
                break;
            }
        }
        if (openBrace !== -1) {
            // Walk forward with brace counting to find matching close
            let depth = 0;
            let closeBrace = -1;
            for (let i = openBrace; i < rawOutput.length; i++) {
                if (rawOutput[i] === '{')
                    depth++;
                else if (rawOutput[i] === '}') {
                    depth--;
                    if (depth === 0) {
                        closeBrace = i;
                        break;
                    }
                }
            }
            if (closeBrace !== -1) {
                const candidate = rawOutput.slice(openBrace, closeBrace + 1);
                try {
                    const parsed = JSON.parse(candidate);
                    if (parsed.version === 1 && parsed.archetype)
                        return applyConstraintDefaults(parsed);
                }
                catch (error) {
                    logger.debug('Completion report brace-count JSON parse failed', { error: summarizeError(error) });
                }
            }
        }
    }
    return null;
}
/**
 * Normalize constraint-related fields on a parsed report:
 * - defaults `constraints` and `constraintFindings` to []
 * - filters malformed entries and records a report issue so drops are observable
 *
 * Pure: returns a new object rather than mutating the input, so callers can
 * share references without surprise writes.
 */
function applyConstraintDefaults(parsed) {
    const next = { ...parsed };
    if (next['archetype'] === 'engineer') {
        const normalized = filterWellFormed(next['constraints'], isWellFormedConstraint);
        next['constraints'] = normalized.items;
        if (normalized.malformedContainer) {
            appendEngineerIssue(next, 'Malformed constraints field ignored: expected an array.');
        }
        else if (normalized.dropped > 0) {
            appendEngineerIssue(next, `Malformed constraints ignored: ${normalized.dropped} entr${normalized.dropped === 1 ? 'y' : 'ies'}.`);
        }
    }
    if (next['archetype'] === 'reviewer') {
        const normalized = filterWellFormed(next['constraintFindings'], isWellFormedConstraintFinding);
        next['constraintFindings'] = normalized.items;
        if (normalized.malformedContainer) {
            appendReviewerIssue(next, 'Malformed constraintFindings field ignored: expected an array.');
        }
        else if (normalized.dropped > 0) {
            appendReviewerIssue(next, `Malformed constraintFindings ignored: ${normalized.dropped} entr${normalized.dropped === 1 ? 'y' : 'ies'}.`);
        }
    }
    return next;
}
