// engine/reverse-engineer/test-file-parser.ts — Parse test files into spec ACs (SPEC-299)
import { readFile } from 'node:fs/promises';
import * as nodePath from 'node:path';
/**
 * Detect the test framework from file content.
 */
export function detectFramework(content) {
    const hasPlaywriterImport = content.toLowerCase().includes('playwright');
    const hasTestDescribe = content.includes('test.describe');
    const hasPlaywright = hasPlaywriterImport || hasTestDescribe;
    if (hasPlaywright) {
        return 'playwright';
    }
    const hasCyDot = content.includes('cy.');
    const hasCypress = hasCyDot;
    if (hasCypress) {
        return 'cypress';
    }
    const hasDescribe = /describe\s*\(/.test(content);
    const hasItOrTest = /(?:it|test)\s*\(/.test(content);
    // hasCyDot and hasPlaywriterImport are already false here (early returns above)
    const hasJest = hasDescribe && hasItOrTest;
    if (hasJest) {
        return 'jest';
    }
    return 'unknown';
}
/**
 * Clean an AC text from a test description:
 * - Remove leading "should " (case-insensitive)
 * - Remove leading "it "
 * - Capitalize first letter
 * - Trim whitespace
 */
export function cleanAcText(description) {
    let text = description.trim();
    text = text.replace(/^should\s+/i, '');
    text = text.replace(/^it\s+/i, '');
    text = text.trim();
    if (text.length > 0) {
        text = text.charAt(0).toUpperCase() + text.slice(1);
    }
    return text;
}
/**
 * Suggest a spec title from an array of describe group names.
 */
export function suggestTitle(groups) {
    if (groups.length === 0) {
        return 'Untitled Spec';
    }
    const unique = [...new Set(groups)];
    if (unique.length >= 2) {
        return `${unique[0]} - ${unique[1]}`;
    }
    return unique[0] ?? 'Untitled Spec';
}
/**
 * Suggest tags from the file path and detected framework.
 */
export function suggestTags(filePath, framework) {
    const tags = [];
    const lower = filePath.toLowerCase();
    if (lower.includes('e2e')) {
        tags.push('e2e');
    }
    if (lower.includes('integration')) {
        tags.push('integration');
    }
    if (lower.includes('unit')) {
        tags.push('unit');
    }
    if (framework !== 'unknown') {
        tags.push(framework);
    }
    if (lower.includes('auth') || lower.includes('login')) {
        tags.push('authentication');
    }
    if (lower.includes('checkout') || lower.includes('payment')) {
        tags.push('payments');
    }
    return [...new Set(tags)];
}
/**
 * Associate each test with the nearest preceding describe block using line numbers.
 */
function buildGroupLineMap(content) {
    const lines = content.split('\n');
    const result = [];
    const groupRegex = /describe\s*\(\s*['"`]([^'"`]+)['"`]/;
    for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        if (line !== undefined) {
            const m = groupRegex.exec(line);
            if (m?.[1] !== undefined) {
                result.push({ lineNumber: i, groupName: m[1] });
            }
        }
    }
    return result;
}
function findGroupForLine(lineNumber, groupMap) {
    let best = 'General';
    for (const entry of groupMap) {
        if (entry.lineNumber <= lineNumber) {
            best = entry.groupName;
        }
    }
    return best;
}
function extractTestFileMatches(content) {
    const lines = content.split('\n');
    const results = [];
    const activeRegex = /(?:^|[^\w])(?:it|test)\s*\(\s*(['"`])([^'"`]+)\1/;
    const skippedRegex = /(?:^|[^\w])(?:it|test)\.skip\s*\(\s*(['"`])([^'"`]+)\1/;
    const xRegex = /(?:^|[^\w])(?:xit|xtest)\s*\(\s*(['"`])([^'"`]+)\1/;
    for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        if (line === undefined) {
            continue;
        }
        const skippedMatch = skippedRegex.exec(line);
        if (skippedMatch?.[2] !== undefined) {
            results.push({ lineNumber: i, description: skippedMatch[2], skipped: true });
            continue;
        }
        const xMatch = xRegex.exec(line);
        if (xMatch?.[2] !== undefined) {
            results.push({ lineNumber: i, description: xMatch[2], skipped: true });
            continue;
        }
        const activeMatch = activeRegex.exec(line);
        if (activeMatch?.[2] !== undefined) {
            results.push({ lineNumber: i, description: activeMatch[2], skipped: false });
        }
    }
    return results;
}
/**
 * Parse a test file and extract acceptance criteria.
 */
export async function parseTestFile(filePath) {
    const content = await readFile(filePath, 'utf-8');
    const framework = detectFramework(content);
    const groupMap = buildGroupLineMap(content);
    const testMatches = extractTestFileMatches(content);
    const generatedAcs = testMatches.map((match) => ({
        text: cleanAcText(match.description),
        group: findGroupForLine(match.lineNumber, groupMap),
        skipped: match.skipped,
    }));
    const skipCount = generatedAcs.filter((ac) => ac.skipped).length;
    const groupNames = [...new Set(groupMap.map((g) => g.groupName))];
    const suggestedTitleValue = suggestTitle(groupNames);
    const suggestedTagsValue = suggestTags(nodePath.normalize(filePath), framework);
    return {
        detectedFramework: framework,
        totalTests: generatedAcs.length,
        skipCount,
        generatedAcs,
        suggestedTitle: suggestedTitleValue,
        suggestedTags: suggestedTagsValue,
    };
}
//# sourceMappingURL=test-file-parser.js.map