/**
 * wrapper-import handler — PR-5a-1
 *
 * Inserts an import / require statement at the top of a TypeScript, JavaScript,
 * or Python source file (after the shebang line, if present).
 *
 * Idempotency: if the exact importStatement string already appears anywhere in
 * the file, the insertion is skipped. For module-level idempotency, we also
 * check whether the module path already appears in a previous import (same
 * package, different named imports).
 *
 * @connexum/ai-governance PR-5a-1
 */
import * as fs from 'fs';
import * as path from 'path';
import { computeUnifiedDiff } from '../diff-utils.js';
/**
 * Compute the file content with the import injected.
 * Returns before + after; caller decides whether to write.
 */
export function applyWrapperImport(agentDir, payload) {
    const filePath = path.resolve(agentDir, payload.targetFile);
    if (!fs.existsSync(filePath)) {
        throw new Error(`wrapper-import: target file not found: ${filePath}`);
    }
    const before = fs.readFileSync(filePath, 'utf-8');
    // Idempotency check: if the import statement already appears verbatim, skip.
    if (before.includes(payload.importStatement)) {
        const relPath = path.relative(agentDir, filePath);
        return {
            filePath,
            before,
            after: before,
            diff: { filePath: relPath, before, after: before, unifiedDiff: '' },
            alreadyApplied: true,
        };
    }
    // Also check for the same module import via a looser pattern.
    const moduleId = extractModuleId(payload.importStatement, payload.language);
    if (moduleId && isModuleAlreadyImported(before, moduleId, payload.language)) {
        const relPath = path.relative(agentDir, filePath);
        return {
            filePath,
            before,
            after: before,
            diff: { filePath: relPath, before, after: before, unifiedDiff: '' },
            alreadyApplied: true,
        };
    }
    const after = injectImport(before, payload.importStatement, payload.language);
    const relPath = path.relative(agentDir, filePath);
    const diff = {
        filePath: relPath,
        before,
        after,
        unifiedDiff: computeUnifiedDiff(before, after, relPath),
    };
    return { filePath, before, after, diff, alreadyApplied: false };
}
/**
 * Write the updated file to disk.
 */
export function writeWrapperImport(agentDir, payload) {
    const result = applyWrapperImport(agentDir, payload);
    if (!result.alreadyApplied) {
        fs.writeFileSync(result.filePath, result.after, 'utf-8');
    }
    return result;
}
// ---------------------------------------------------------------------------
// Import injection
// ---------------------------------------------------------------------------
function injectImport(content, importStatement, language) {
    const lines = content.split('\n');
    // Find insertion point: after shebang (line 0 if it starts with #!),
    // and after any leading file-level docstring (Python triple-quote blocks).
    let insertAt = 0;
    if (lines[0]?.startsWith('#!')) {
        insertAt = 1;
    }
    if (language === 'python') {
        // Skip over leading module-level docstring (triple-quoted)
        insertAt = skipPythonDocstring(lines, insertAt);
    }
    else {
        // Skip over leading block comment / JSDoc /** ... */
        insertAt = skipBlockComment(lines, insertAt);
    }
    const result = [
        ...lines.slice(0, insertAt),
        importStatement,
        ...lines.slice(insertAt),
    ];
    return result.join('\n');
}
/**
 * Skip a Python triple-quoted docstring at `startIdx`.
 * Returns the index of the first line after the docstring.
 */
function skipPythonDocstring(lines, startIdx) {
    const first = lines[startIdx]?.trimStart();
    if (!first?.startsWith('"""') && !first?.startsWith("'''")) {
        return startIdx;
    }
    const quote = first.startsWith('"""') ? '"""' : "'''";
    // Single-line docstring: """...""" on one line
    const rest = first.slice(3);
    if (rest.includes(quote))
        return startIdx + 1;
    // Multi-line: scan for the closing quotes
    for (let i = startIdx + 1; i < lines.length; i++) {
        if (lines[i].includes(quote))
            return i + 1;
    }
    return startIdx; // Malformed — don't skip
}
/**
 * Skip a leading block comment (slash-star) in JS/TS.
 */
function skipBlockComment(lines, startIdx) {
    const first = lines[startIdx]?.trimStart();
    if (!first?.startsWith('/*'))
        return startIdx;
    for (let i = startIdx; i < lines.length; i++) {
        if (lines[i].includes('*/'))
            return i + 1;
    }
    return startIdx;
}
// ---------------------------------------------------------------------------
// Idempotency helpers
// ---------------------------------------------------------------------------
/**
 * Extract the module path from an import statement.
 * e.g. "import { Foo } from '@connexum/ai-governance';" → "@connexum/ai-governance"
 * e.g. "from connexum.pii_shield import shield" → "connexum.pii_shield"
 */
function extractModuleId(importStatement, language) {
    if (language === 'python') {
        const m = importStatement.match(/^from\s+([\w.]+)\s+import/);
        return m ? m[1] : null;
    }
    // TS/JS: from 'module' or require('module')
    const m = importStatement.match(/from\s+['"]([^'"]+)['"]/) ??
        importStatement.match(/require\s*\(\s*['"]([^'"]+)['"]\s*\)/);
    return m ? m[1] : null;
}
/**
 * Check if a module is already imported in the file (loose match).
 */
function isModuleAlreadyImported(content, moduleId, language) {
    if (language === 'python') {
        return (content.includes(`from ${moduleId} import`) ||
            content.includes(`import ${moduleId}`));
    }
    return (content.includes(`from '${moduleId}'`) ||
        content.includes(`from "${moduleId}"`) ||
        content.includes(`require('${moduleId}')`) ||
        content.includes(`require("${moduleId}")`));
}
//# sourceMappingURL=wrapper-import.js.map