/**
 * AI Code Verification Module
 *
 * Orchestrates AI code detection, hallucination checking,
 * and confidence scoring for production readiness certification.
 *
 * @module scanners/ai-code
 */
import { readFile, readdir } from "fs/promises";
import { glob } from "glob";
import { join, relative, extname } from "path";
import { AIVerifyConfigSchema } from "./types.js";
import { detectAIPatterns, patternMatchesToIndicators, calculateAILikelihood, } from "./ai-detector.js";
import { checkFileForHallucinations, } from "./hallucination-checker.js";
import { scoreAllChanges, calculateDetectionScore, calculateReviewScore, calculateOverallScore, groupByReviewPriority, calculateHallucinationScore as calculateHallucinationScoreFromChanges, } from "./confidence-scorer.js";
export * from "./types.js";
export * from "./ai-detector.js";
export { parseImports, checkRelativeImport, checkPackageImport, checkDeprecatedAPIs, checkMixedFrameworks, checkFileForHallucinations, scanDirectoryForHallucinations, } from "./hallucination-checker.js";
export { scoreChange, scoreAllChanges, calculateDetectionScore, calculateReviewScore, calculateOverallScore, determineReviewPriority, groupByReviewPriority, calculateHallucinationScore, } from "./confidence-scorer.js";
export async function loadAIVerifyConfig(projectPath) {
    const configPaths = [
        join(projectPath, ".vaspera", "ai-verify.yaml"),
        join(projectPath, ".vaspera", "ai-verify.yml"),
        join(projectPath, ".vaspera", "ai-verify.json"),
    ];
    for (const configPath of configPaths) {
        try {
            const content = await readFile(configPath, "utf-8");
            let parsed;
            if (configPath.endsWith(".json")) {
                parsed = JSON.parse(content);
            }
            else {
                const yaml = await import("yaml");
                parsed = yaml.parse(content);
            }
            return AIVerifyConfigSchema.parse(parsed);
        }
        catch {
            continue;
        }
    }
    return null;
}
export async function generateAIVerifyConfig(projectPath) {
    const configDir = join(projectPath, ".vaspera");
    const configPath = join(configDir, "ai-verify.yaml");
    const yaml = await import("yaml");
    const defaultConfig = {
        detection: {
            checkPatterns: true,
            checkComments: true,
            checkImports: true,
            checkMetadata: true,
        },
        hallucination: {
            checkImports: true,
            checkApis: true,
            checkVersions: true,
            packageRegistry: "npm",
        },
        review: {
            requireForConfidence: "medium",
            requireForHallucinations: true,
            autoApproveBelow: 30,
        },
        exclude: [
            "node_modules",
            "dist",
            "build",
            ".git",
            "coverage",
            "*.test.*",
            "*.spec.*",
        ],
    };
    const { mkdir, writeFile } = await import("fs/promises");
    await mkdir(configDir, { recursive: true });
    await writeFile(configPath, yaml.stringify(defaultConfig), "utf-8");
    return configPath;
}
async function buildDiagnostics(projectPath, extensions, exclude) {
    const suggestions = [];
    const searchedDirs = [];
    const pattern = `**/*.{${extensions.join(",")}}`;
    const allFiles = await glob(pattern, {
        cwd: projectPath,
        absolute: true,
    });
    const filesWithoutExclude = allFiles.length;
    const filesAfterExclude = await glob(pattern, {
        cwd: projectPath,
        ignore: exclude.map((e) => `**/${e}/**`),
        absolute: true,
    });
    let reason;
    if (filesWithoutExclude === 0) {
        reason = `No files matching extensions [${extensions.join(", ")}] found in project`;
        const allExtensions = new Set();
        const anyFiles = await glob("**/*.*", {
            cwd: projectPath,
            ignore: ["**/node_modules/**", "**/.git/**"],
            absolute: true,
        });
        for (const f of anyFiles.slice(0, 1000)) {
            const ext = extname(f).replace(".", "").toLowerCase();
            if (ext)
                allExtensions.add(ext);
        }
        const available = Array.from(allExtensions).slice(0, 10);
        if (available.length > 0) {
            suggestions.push(`Found file extensions: ${available.join(", ")}`);
            suggestions.push(`Try: extensions: [${available.map((e) => `"${e}"`).join(", ")}]`);
        }
    }
    else if (filesAfterExclude.length === 0) {
        reason = `Found ${filesWithoutExclude} files, but all were excluded by patterns: ${exclude.join(", ")}`;
        suggestions.push("Review exclude patterns - they may be too broad");
        suggestions.push(`Excluded ${filesWithoutExclude} files`);
    }
    else {
        reason = "Unknown reason for 0 files";
    }
    try {
        const entries = await readdir(projectPath, { withFileTypes: true });
        for (const entry of entries) {
            if (entry.isDirectory() && !entry.name.startsWith(".")) {
                searchedDirs.push(entry.name);
            }
        }
    }
    catch {
        searchedDirs.push("(could not list directories)");
    }
    return {
        reason,
        suggestions,
        searchedDirectories: searchedDirs.slice(0, 10),
        extensionsUsed: extensions,
        excludePatterns: exclude,
        filesFoundBeforeExclude: filesWithoutExclude,
    };
}
export async function runAIVerification(projectPath, options = {}) {
    const startTime = Date.now();
    const config = options.config ?? (await loadAIVerifyConfig(projectPath)) ?? {};
    const extensions = options.extensions ?? ["ts", "tsx", "js", "jsx", "py", "go", "rb"];
    const exclude = options.exclude ?? config.exclude ?? [
        "node_modules", "dist", ".git", "build", "coverage",
    ];
    let filesToAnalyze;
    if (options.files && options.files.length > 0) {
        filesToAnalyze = options.files.map((f) => f.startsWith("/") ? f : join(projectPath, f));
    }
    else {
        const pattern = `**/*.{${extensions.join(",")}}`;
        filesToAnalyze = await glob(pattern, {
            cwd: projectPath,
            ignore: exclude.map((e) => `**/${e}/**`),
            absolute: true,
        });
    }
    if (filesToAnalyze.length === 0) {
        const diagnostics = await buildDiagnostics(projectPath, extensions, exclude);
        const duration = Date.now() - startTime;
        return {
            success: true,
            filesAnalyzed: 0,
            changesScored: [],
            hallucinations: [],
            indicators: [],
            summary: {
                totalChanges: 0,
                aiLikelyChanges: 0,
                requiresReview: 0,
                hallucinationsFound: 0,
                averageConfidence: 100,
            },
            score: {
                detectionScore: 100,
                hallucinationScore: 100,
                reviewScore: 100,
                overallScore: 100,
            },
            duration,
            diagnostics,
        };
    }
    const allIndicators = [];
    const allHallucinations = [];
    const changeInputs = [];
    for (const filePath of filesToAnalyze) {
        try {
            const content = await readFile(filePath, "utf-8");
            const lineCount = content.split("\n").length;
            const patterns = await detectAIPatterns(filePath, content);
            const fileIndicators = patternMatchesToIndicators(patterns);
            allIndicators.push(...fileIndicators);
            const fileHallucinations = await checkFileForHallucinations(filePath, projectPath, content);
            allHallucinations.push(...fileHallucinations);
            changeInputs.push({
                file: relative(projectPath, filePath),
                startLine: 1,
                endLine: lineCount,
                changeType: "modified",
                indicators: fileIndicators,
                hallucinations: fileHallucinations,
            });
        }
        catch {
            continue;
        }
    }
    const { scoredChanges, summary } = scoreAllChanges(changeInputs, config);
    const detectionScore = calculateDetectionScore(scoredChanges);
    const hallucinationScore = calculateHallucinationScoreFromChanges(scoredChanges);
    const reviewScore = calculateReviewScore(scoredChanges);
    const overallScore = calculateOverallScore({
        detectionScore,
        hallucinationScore,
        reviewScore,
    });
    const duration = Date.now() - startTime;
    return {
        success: true,
        filesAnalyzed: filesToAnalyze.length,
        changesScored: scoredChanges,
        hallucinations: allHallucinations,
        indicators: allIndicators,
        summary,
        score: {
            detectionScore,
            hallucinationScore,
            reviewScore,
            overallScore,
        },
        duration,
    };
}
export async function quickAICheck(filePath, projectPath) {
    const content = await readFile(filePath, "utf-8");
    const patterns = await detectAIPatterns(filePath, content);
    const indicators = patternMatchesToIndicators(patterns);
    const hallucinations = await checkFileForHallucinations(filePath, projectPath, content);
    const aiLikelihood = calculateAILikelihood(indicators);
    const requiresReview = aiLikelihood >= 30 || hallucinations.length > 0;
    return {
        aiLikelihood,
        hallucinations: hallucinations.length,
        requiresReview,
        indicators,
    };
}
export function formatVerificationReport(result) {
    const lines = [];
    lines.push("AI Code Verification Report");
    lines.push("===========================");
    lines.push("");
    lines.push(`Files analyzed: ${result.filesAnalyzed}`);
    lines.push(`Duration: ${result.duration}ms`);
    lines.push("");
    lines.push("Summary:");
    lines.push(`  Total changes scored: ${result.summary.totalChanges}`);
    lines.push(`  AI-likely changes: ${result.summary.aiLikelyChanges}`);
    lines.push(`  Requires review: ${result.summary.requiresReview}`);
    lines.push(`  Hallucinations found: ${result.summary.hallucinationsFound}`);
    lines.push(`  Average confidence: ${result.summary.averageConfidence}%`);
    lines.push("");
    lines.push("Scores:");
    lines.push(`  Detection Score: ${result.score.detectionScore}/100 (lower AI likelihood = better)`);
    lines.push(`  Hallucination Score: ${result.score.hallucinationScore}/100 (fewer hallucinations = better)`);
    lines.push(`  Review Score: ${result.score.reviewScore}/100 (fewer reviews = better)`);
    lines.push(`  Overall Score: ${result.score.overallScore}/100`);
    lines.push("");
    if (result.hallucinations.length > 0) {
        lines.push("Hallucinations:");
        for (const h of result.hallucinations.slice(0, 10)) {
            lines.push(`  - [${h.severity.toUpperCase()}] ${h.description}`);
            lines.push(`    at ${h.location.file}:${h.location.line}`);
            if (h.suggestion) {
                lines.push(`    Fix: ${h.suggestion}`);
            }
        }
        if (result.hallucinations.length > 10) {
            lines.push(`  ... and ${result.hallucinations.length - 10} more`);
        }
        lines.push("");
    }
    const byPriority = groupByReviewPriority(result.changesScored);
    const needsReview = [
        ...byPriority.critical,
        ...byPriority.high,
        ...byPriority.medium,
    ];
    if (needsReview.length > 0) {
        lines.push("Changes requiring review:");
        for (const change of needsReview.slice(0, 10)) {
            const priority = change.hallucinations.some((h) => h.severity === "critical")
                ? "CRITICAL"
                : change.confidence.toUpperCase();
            lines.push(`  - [${priority}] ${change.file} (${change.aiLikelihood}% AI likelihood)`);
            if (change.reviewReason) {
                lines.push(`    Reason: ${change.reviewReason}`);
            }
        }
        if (needsReview.length > 10) {
            lines.push(`  ... and ${needsReview.length - 10} more`);
        }
    }
    return lines.join("\n");
}
//# sourceMappingURL=index.js.map