import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import { createHash } from 'crypto';
/**
 * Captures exec_command validation regressions into a golden samples structure.
 *
 * Trigger: exec_command validation failure (shape/JSON/required fields)
 *
 * Default destination:
 *   ~/.routecodex/golden_samples/ci-regression/exec_command/<error-type>/
 *
 * Optional repo destination (explicit opt-in):
 *   ROUTECODEX_EXEC_COMMAND_REGRESSION_TO_REPO=1
 *   → <repoRoot>/samples/ci-goldens/_regressions/exec_command/<error-type>/
 *
 * Explicit override:
 *   ROUTECODEX_EXEC_COMMAND_REGRESSION_DIR=/abs/path
 *
 * Note: we intentionally redact obvious secrets from captured payloads.
 */
const MAX_SAMPLES_PER_TYPE = 50;
function detectRepoRootFromCwd() {
    try {
        let dir = process.cwd();
        for (let i = 0; i < 12; i += 1) {
            const marker = path.join(dir, 'samples', 'ci-goldens');
            const pkg = path.join(dir, 'package.json');
            if (fs.existsSync(marker) && fs.existsSync(pkg)) {
                try {
                    const raw = fs.readFileSync(pkg, 'utf-8');
                    const json = JSON.parse(raw);
                    if (json && typeof json === 'object' && String(json.name || '') === 'routecodex') {
                        return dir;
                    }
                }
                catch {
                    // ignore parse errors
                }
            }
            const parent = path.dirname(dir);
            if (parent === dir)
                break;
            dir = parent;
        }
    }
    catch {
        // ignore
    }
    return null;
}
function resolveSamplesRoot() {
    const explicit = String(process?.env?.ROUTECODEX_EXEC_COMMAND_REGRESSION_DIR || '').trim();
    if (explicit) {
        return path.resolve(explicit);
    }
    const toRepo = String(process?.env?.ROUTECODEX_EXEC_COMMAND_REGRESSION_TO_REPO || '').trim() === '1';
    if (toRepo) {
        const repoRoot = detectRepoRootFromCwd();
        if (repoRoot) {
            return path.join(repoRoot, 'samples', 'ci-goldens', '_regressions', 'exec_command');
        }
    }
    return path.join(os.homedir(), '.routecodex', 'golden_samples', 'ci-regression', 'exec_command');
}
function stableSampleId(sample) {
    const key = `${String(sample.errorType || 'unknown')}:` +
        `${String(sample.originalArgs ?? '')}:` +
        `${String(sample.normalizedArgs ?? '')}:` +
        `${String(sample.validationError ?? '')}`;
    return createHash('sha1').update(key).digest('hex').slice(0, 16);
}
function redactSecrets(text) {
    if (!text)
        return text;
    let next = text;
    // Common API key formats (best-effort).
    next = next.replace(/\bsk-[A-Za-z0-9_-]{10,}\b/g, 'sk-<REDACTED>');
    next = next.replace(/\bcr_[A-Za-z0-9]{20,}\b/g, 'cr_<REDACTED>');
    next = next.replace(/\bAIza[0-9A-Za-z_-]{20,}\b/g, 'AIza<REDACTED>');
    // Authorization headers.
    next = next.replace(/(authorization"?\s*:\s*"?bearer\s+)[^"]+/gi, '$1<REDACTED>');
    next = next.replace(/(authorization:\s*bearer\s+)[^\s]+/gi, '$1<REDACTED>');
    // Shell exports of *_KEY/*_TOKEN/*_SECRET.
    next = next.replace(/(\bexport\s+[A-Z0-9_]*(?:KEY|TOKEN|SECRET)[A-Z0-9_]*=)[^\s'"]+/gi, '$1<REDACTED>');
    return next;
}
function sanitizeArgs(raw) {
    const trimmed = String(raw || '');
    if (!trimmed)
        return trimmed;
    // If it's JSON, redact known sensitive fields (cmd) aggressively.
    try {
        const obj = JSON.parse(trimmed);
        if (obj && typeof obj === 'object') {
            const cloned = Array.isArray(obj) ? obj.slice() : { ...obj };
            if (typeof cloned.cmd === 'string') {
                const cmdText = String(cloned.cmd);
                cloned.cmd = redactSecrets(cmdText).slice(0, 500);
            }
            return redactSecrets(JSON.stringify(cloned, null, 2));
        }
    }
    catch {
        // ignore JSON parse errors
    }
    return redactSecrets(trimmed);
}
export function captureExecCommandRegression(sample) {
    try {
        const root = resolveSamplesRoot();
        const safeType = String(sample.errorType || 'unknown').replace(/[^a-z0-9-]/gi, '_');
        const typeDir = path.join(root, safeType);
        if (!fs.existsSync(typeDir)) {
            fs.mkdirSync(typeDir, { recursive: true });
        }
        try {
            const existing = fs.readdirSync(typeDir).filter((f) => f.endsWith('.json'));
            if (existing.length >= MAX_SAMPLES_PER_TYPE)
                return;
        }
        catch {
            // ignore
        }
        const sanitized = {
            ...sample,
            originalArgs: sanitizeArgs(sample.originalArgs),
            normalizedArgs: typeof sample.normalizedArgs === 'string' ? sanitizeArgs(sample.normalizedArgs) : sample.normalizedArgs
        };
        const id = `sample_${stableSampleId(sanitized)}`;
        const file = path.join(typeDir, `${id}.json`);
        if (fs.existsSync(file))
            return;
        const fullSample = {
            id,
            timestamp: new Date().toISOString(),
            ...sanitized
        };
        fs.writeFileSync(file, JSON.stringify(fullSample, null, 2), 'utf-8');
    }
    catch {
        // Silently fail to avoid disrupting runtime
    }
}
