// engine/spec-format/lean-spec-generator.ts — Generates lean spec.md with YAML frontmatter (SPEC-461)
// Output: ~30-50 lines. No generic sections, no OWASP, no STRIDE, no resilience criteria.
import { parseBddScenarios, renderBddScenariosYaml, convertCheckboxToBdd } from './bdd-parser.js';
import { deriveModelBudget } from './model-budget-deriver.js';
import { renderHistoryYaml } from '../spec-versioning/render-history.js';
import { renderGroundingFrontmatter, renderTechnicalReferenceGroundingFrontmatter, } from '../spec-grounding/contract.js';
/** Strip redundant "SPEC-XXX — " or "SPEC-XXX: " prefix from spec titles.
 * Titles must not repeat the ID since it is already stored in the `id` field. */
function sanitizeTitle(title, specId) {
    // Match "SPEC-123 — ", "SPEC-123: ", "SPEC-123 - " at the start
    const prefixRegex = new RegExp(`^${specId}\\s*[—:\\-]\\s*`, 'i');
    return title.replace(prefixRegex, '').trim();
}
/** Generate lean spec.md content: YAML frontmatter + user description only. */
export function generateLeanSpecContent(input) {
    const { spec, description, estimation, extraCriteria = [], acFormat = 'checkbox' } = input;
    const now = spec.createdAt.slice(0, 10); // YYYY-MM-DD
    const cleanTitle = sanitizeTitle(spec.title, spec.id);
    const history = [{ date: now, event: 'created' }];
    const { model, budget } = deriveModelBudget(spec.difficulty, estimation.devHours);
    const frontmatterBase = [
        '---',
        `id: ${spec.id}`,
        ...(spec.uuid ? [`uuid: ${spec.uuid}`] : []),
        ...(spec.idempotencyKey ? [`idempotencyKey: ${spec.idempotencyKey}`] : []),
        `title: "${escapeYaml(cleanTitle)}"`,
        `status: ${spec.status}`,
        `type: ${spec.type}`,
        `target: ${spec.target}`,
        `scope: ${spec.scope}`,
        `difficulty: ${String(spec.difficulty)}`,
        `risk: ${spec.risk}`,
        `tags: [${spec.tags.join(', ')}]`,
        `branch: ${spec.gitBranch}`,
        `created: ${now}`,
        // SPEC-717: spec format versioning fields
        `spec_format_version: "1.0"`,
        `spec_version: "1.0.0"`,
        `estimation:`,
        `  devHours: ${String(estimation.devHours)}`,
        `  reviewHours: ${String(estimation.reviewHours)}`,
        `  cost: ${String(estimation.totalCostUsd)}`,
        `  model: ${estimation.recommendedModel}`,
        `model: ${model}`,
        `budget: ${String(budget)}`,
        ...(spec.generatedWithModel ? [`generatedWithModel: ${spec.generatedWithModel}`] : []),
        ...(spec.generatedAt ? [`generatedAt: ${spec.generatedAt}`] : []),
        ...(spec.qualityWarnings && spec.qualityWarnings.length > 0
            ? [`qualityWarnings: ${JSON.stringify(spec.qualityWarnings)}`]
            : []),
        ...(input.groundingCriteria ? renderGroundingFrontmatter(input.groundingCriteria) : []),
        ...(input.groundingTechnicalReferences
            ? renderTechnicalReferenceGroundingFrontmatter(input.groundingTechnicalReferences)
            : []),
    ];
    let acLines;
    if (acFormat === 'bdd') {
        acLines = buildBddLines(description, extraCriteria, input.criteriaOverride, input.scenarioTestPaths ?? []);
    }
    else {
        acLines = buildCheckboxLines(description, extraCriteria, input.criteriaOverride);
    }
    // SPEC-717: render empty version history for new specs
    const historyYaml = renderHistoryYaml([]);
    const lines = [
        ...frontmatterBase,
        ...acLines,
        'history:',
        ...history.map((h) => `  - date: ${h.date}\n    event: ${h.event}`),
        // SPEC-717: version history (empty for new specs)
        historyYaml,
        '---',
        '',
        description.trim(),
        '',
    ];
    return lines.join('\n');
}
/** Build checkbox-format criteria lines. */
function buildCheckboxLines(description, extraCriteria, criteriaOverride) {
    const criteria = criteriaOverride ?? [
        ...extractCriteria(description),
        ...extraCriteria.map((text) => ({ text, done: false })),
    ];
    return [
        'criteria:',
        ...criteria.map((c) => `  - text: "${escapeYaml(c.text)}"\n    done: ${String(c.done)}`),
    ];
}
/** Build BDD scenario lines. */
function buildBddLines(description, extraCriteria, criteriaOverride, scenarioTestPaths) {
    let scenarios = parseBddScenarios(description);
    // Fallback: convert checkbox criteria to BDD scenarios
    if (scenarios.length === 0) {
        const checkboxCriteria = criteriaOverride ?? [
            ...extractCriteria(description),
            ...extraCriteria.map((text) => ({ text, done: false })),
        ];
        scenarios = convertCheckboxToBdd(checkboxCriteria);
    }
    else {
        // Append extra criteria as additional scenarios
        for (const text of extraCriteria) {
            scenarios.push({
                title: text,
                steps: [{ keyword: 'then', text }],
                done: false,
            });
        }
    }
    if (scenarioTestPaths.length > 0) {
        scenarios = scenarios.map((scenario) => ({
            ...scenario,
            tests: scenario.tests && scenario.tests.length > 0
                ? scenario.tests
                : scenarioTestPaths.map((path) => ({ path })),
        }));
    }
    return renderBddScenariosYaml(scenarios);
}
/** Extract acceptance criteria from description. Looks for checkbox patterns or generates a default.
 * Priority: checkboxes > GIVEN/WHEN/THEN > plain list items > fallback. */
export function extractCriteria(description) {
    const checkboxCriteria = extractCheckboxCriteria(description);
    if (checkboxCriteria.length > 0) {
        return checkboxCriteria;
    }
    const gwtCriteria = extractGivenWhenThenCriteria(description);
    if (gwtCriteria.length > 0) {
        return gwtCriteria;
    }
    const plainListCriteria = extractPlainListCriteria(description);
    if (plainListCriteria.length > 0) {
        return plainListCriteria;
    }
    return [
        {
            text: 'Define acceptance criteria — autopilot could not infer testable behavior from the description',
            done: false,
        },
    ];
}
/** Extract checkbox-style criteria: `- [ ] text` or `- [x] text`. */
function extractCheckboxCriteria(description) {
    const criteria = [];
    const checkboxRegex = /^[-*]\s*\[([ xX])\]\s*(.+)$/gm;
    let match = checkboxRegex.exec(description);
    while (match) {
        criteria.push({
            text: match[2]?.trim() ?? '',
            done: match[1]?.toLowerCase() === 'x',
        });
        match = checkboxRegex.exec(description);
    }
    return criteria;
}
/** Extract GIVEN/WHEN/THEN patterns. Supports:
 * - Single-line: `GIVEN X WHEN Y THEN Z`
 * - Multi-line: `Given X\nWhen Y\nThen Z`
 * Returns the THEN segment as criterion text. */
function extractGivenWhenThenCriteria(description) {
    const criteria = [];
    // Single-line: GIVEN ... WHEN ... THEN ...
    const singleLineRegex = /GIVEN\s+.+\s+WHEN\s+.+\s+THEN\s+(.+)/gi;
    let match = singleLineRegex.exec(description);
    while (match) {
        const thenText = match[1]?.trim() ?? '';
        if (thenText) {
            criteria.push({ text: thenText, done: false });
        }
        match = singleLineRegex.exec(description);
    }
    if (criteria.length > 0) {
        return criteria;
    }
    // Multi-line: Given ...\nWhen ...\nThen ...
    const multiLineRegex = /^Given\s+.+\n^When\s+.+\n^Then\s+(.+)/gim;
    let mlMatch = multiLineRegex.exec(description);
    while (mlMatch) {
        const thenText = mlMatch[1]?.trim() ?? '';
        if (thenText) {
            criteria.push({ text: thenText, done: false });
        }
        mlMatch = multiLineRegex.exec(description);
    }
    return criteria;
}
/** Extract plain list items: `- text` or `* text` (no checkboxes).
 * Only used when no checkboxes or GIVEN/WHEN/THEN are found. */
function extractPlainListCriteria(description) {
    const criteria = [];
    // Plain list: `- text` or `* text`, not followed by `[`
    const plainListRegex = /^[-*]\s+(?!\[)(.+)$/gm;
    let match = plainListRegex.exec(description);
    while (match) {
        const text = match[1]?.trim() ?? '';
        if (text) {
            criteria.push({ text, done: false });
        }
        match = plainListRegex.exec(description);
    }
    return criteria;
}
/** Escape double quotes in YAML string values. */
function escapeYaml(value) {
    return value.replace(/"/g, '\\"');
}
//# sourceMappingURL=lean-spec-generator.js.map