import { readFileSync, existsSync } from 'fs';
import { join } from 'path';
import { consoleLogger } from '../../utils/logger.js';
/**
 * Validate AC presence in increment spec.md
 *
 * **Checks**:
 * 1. spec.md exists
 * 2. spec.md contains "## Acceptance Criteria" section
 * 3. AC count matches metadata.json (if metadata exists)
 * 4. All ACs follow proper format: `- [ ] **AC-US1-01**: Title`
 *
 * @param incrementPath - Path to increment directory
 * @param options - Validation options
 * @returns Validation result
 */
export function validateACPresence(incrementPath, options = {}) {
    const logger = options.logger ?? consoleLogger;
    const strict = options.strict ?? true;
    const result = {
        valid: true,
        acCount: 0,
        expectedCount: 0,
        errors: [],
        warnings: [],
    };
    // 1. Check spec.md exists
    const specPath = join(incrementPath, 'spec.md');
    if (!existsSync(specPath)) {
        result.valid = false;
        result.errors.push(`spec.md not found: ${specPath}`);
        return result;
    }
    const specContent = readFileSync(specPath, 'utf-8');
    // 2. Check for "## Acceptance Criteria" section
    if (!specContent.includes('## Acceptance Criteria')) {
        result.valid = false;
        result.errors.push('spec.md missing "## Acceptance Criteria" section');
        result.suggestedFix = `Add ACs inline to spec.md (format: - [ ] **AC-US1-01**: Title)`;
    }
    // 3. Count ACs in spec.md
    const acMatches = specContent.match(/^- \[[x ]\] \*\*AC-US\d+-\d+\*\*:/gm);
    result.acCount = acMatches ? acMatches.length : 0;
    if (result.acCount === 0) {
        result.valid = false;
        result.errors.push('spec.md contains 0 Acceptance Criteria');
        result.suggestedFix = `Add ACs inline to spec.md (format: - [ ] **AC-US1-01**: Title)`;
    }
    // 4. Check metadata.json for expected AC count
    const metadataPath = join(incrementPath, 'metadata.json');
    if (existsSync(metadataPath)) {
        try {
            const metadata = JSON.parse(readFileSync(metadataPath, 'utf-8'));
            result.expectedCount = metadata.total_acs ?? 0;
            if (result.expectedCount > 0 && result.acCount !== result.expectedCount) {
                const message = `AC count mismatch: spec.md has ${result.acCount} ACs, metadata.json expects ${result.expectedCount}`;
                if (strict) {
                    result.valid = false;
                    result.errors.push(message);
                }
                else {
                    result.warnings.push(message);
                }
            }
            if (result.expectedCount === 0 && result.acCount > 0) {
                result.warnings.push(`metadata.json has total_acs=0 but spec.md contains ${result.acCount} ACs - metadata may need update`);
            }
        }
        catch (err) {
            result.warnings.push(`Could not parse metadata.json: ${err.message}`);
        }
    }
    // 5. Validate AC format
    const invalidACs = [];
    const lines = specContent.split('\n');
    for (const [index, line] of lines.entries()) {
        if (line.includes('**AC-US') && !line.match(/^- \[[x ]\] \*\*AC-US\d+-\d+\*\*:/)) {
            invalidACs.push(`Line ${index + 1}: "${line.substring(0, 60)}..."`);
        }
    }
    if (invalidACs.length > 0) {
        result.warnings.push(`Found ${invalidACs.length} ACs with invalid format`);
        if (invalidACs.length <= 3) {
            result.warnings.push(...invalidACs);
        }
    }
    // 6. Check for "structure: user-stories" pattern
    const frontmatterMatch = specContent.match(/^---\n([\s\S]*?)\n---/);
    if (frontmatterMatch) {
        const frontmatter = frontmatterMatch[1];
        if (frontmatter.includes('structure: user-stories') && result.acCount === 0) {
            result.errors.push('⚠️  CRITICAL: spec.md uses `structure: user-stories` but contains NO inline ACs');
            result.errors.push('   AC sync hooks require ACs in spec.md even when using external living docs');
            result.suggestedFix = `Add ACs inline to spec.md from living docs (format: - [ ] **AC-US1-01**: Title)`;
            result.valid = false;
        }
    }
    return result;
}
/**
 * Format validation result as human-readable message
 */
export function formatValidationResult(result) {
    const lines = [];
    if (result.valid) {
        lines.push(`✅ AC Presence Validation: PASSED`);
        lines.push(`   ✓ ${result.acCount} Acceptance Criteria found in spec.md`);
        if (result.expectedCount > 0) {
            lines.push(`   ✓ Matches metadata.json (${result.expectedCount} expected)`);
        }
    }
    else {
        lines.push(`❌ AC Presence Validation: FAILED`, '');
        if (result.errors.length > 0) {
            lines.push(`ERRORS (${result.errors.length}):`);
            for (const error of result.errors) {
                lines.push(`  🔴 ${error}`);
            }
            lines.push('');
        }
        if (result.suggestedFix) {
            lines.push(`💡 SUGGESTED FIX:`);
            lines.push(`   ${result.suggestedFix}`, '');
        }
    }
    if (result.warnings.length > 0) {
        lines.push(`WARNINGS (${result.warnings.length}):`);
        for (const warning of result.warnings) {
            lines.push(`  🟡 ${warning}`);
        }
    }
    return lines.join('\n');
}
/**
 * Validate AC presence and throw if validation fails
 *
 * Use this in critical paths (e.g., before starting increment)
 */
export function validateACPresenceStrict(incrementPath, logger = consoleLogger) {
    const result = validateACPresence(incrementPath, { logger, strict: true });
    if (!result.valid) {
        const formattedResult = formatValidationResult(result);
        logger.error(formattedResult);
        throw new Error(`AC presence validation failed for ${incrementPath}`);
    }
    logger.log(formatValidationResult(result));
}
//# sourceMappingURL=ac-presence-validator.js.map