"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.modelAuditRouter = void 0;
const child_process_1 = require("child_process");
const child_process_2 = require("child_process");
const express_1 = require("express");
const fs_1 = __importDefault(require("fs"));
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const util_1 = require("util");
const logger_1 = __importDefault(require("../../logger"));
const telemetry_1 = __importDefault(require("../../telemetry"));
const execAsync = (0, util_1.promisify)(child_process_1.exec);
exports.modelAuditRouter = (0, express_1.Router)();
// Check if modelaudit is installed
exports.modelAuditRouter.get('/check-installed', async (req, res) => {
    try {
        await execAsync('python -c "import modelaudit"');
        res.json({ installed: true, cwd: process.cwd() });
    }
    catch {
        res.json({ installed: false, cwd: process.cwd() });
    }
});
// Check path type
exports.modelAuditRouter.post('/check-path', async (req, res) => {
    try {
        const { path: inputPath } = req.body;
        if (!inputPath) {
            res.status(400).json({ error: 'No path provided' });
            return;
        }
        // Handle home directory expansion
        let expandedPath = inputPath;
        if (expandedPath.startsWith('~/')) {
            expandedPath = path_1.default.join(os_1.default.homedir(), expandedPath.slice(2));
        }
        const absolutePath = path_1.default.isAbsolute(expandedPath)
            ? expandedPath
            : path_1.default.resolve(process.cwd(), expandedPath);
        // Check if path exists
        if (!fs_1.default.existsSync(absolutePath)) {
            res.json({ exists: false, type: null });
            return;
        }
        // Get path stats
        const stats = fs_1.default.statSync(absolutePath);
        const type = stats.isDirectory() ? 'directory' : 'file';
        res.json({
            exists: true,
            type,
            absolutePath,
            name: path_1.default.basename(absolutePath),
        });
    }
    catch (error) {
        logger_1.default.error(`Error checking path: ${error}`);
        res.status(500).json({ error: String(error) });
    }
});
// Run model scan
exports.modelAuditRouter.post('/scan', async (req, res) => {
    try {
        const { paths, options } = req.body;
        if (!paths || !Array.isArray(paths) || paths.length === 0) {
            res.status(400).json({ error: 'No paths provided' });
            return;
        }
        // Check if modelaudit is installed
        try {
            await execAsync('python -c "import modelaudit"');
        }
        catch {
            res.status(400).json({
                error: 'ModelAudit is not installed. Please install it using: pip install modelaudit',
            });
            return;
        }
        // Resolve paths to absolute paths
        const resolvedPaths = [];
        for (const inputPath of paths) {
            // Skip empty paths
            if (!inputPath || inputPath.trim() === '') {
                continue;
            }
            // Handle home directory expansion
            let expandedPath = inputPath;
            if (expandedPath.startsWith('~/')) {
                expandedPath = path_1.default.join(os_1.default.homedir(), expandedPath.slice(2));
            }
            const absolutePath = path_1.default.isAbsolute(expandedPath)
                ? expandedPath
                : path_1.default.resolve(process.cwd(), expandedPath);
            // Check if path exists
            if (!fs_1.default.existsSync(absolutePath)) {
                res
                    .status(400)
                    .json({ error: `Path does not exist: ${inputPath} (resolved to: ${absolutePath})` });
                return;
            }
            resolvedPaths.push(absolutePath);
        }
        if (resolvedPaths.length === 0) {
            res.status(400).json({ error: 'No valid paths to scan' });
            return;
        }
        // Build command arguments
        const args = ['scan'];
        // Add resolved paths
        args.push(...resolvedPaths);
        // Add options
        if (options.blacklist && Array.isArray(options.blacklist)) {
            options.blacklist.forEach((pattern) => {
                args.push('--blacklist', pattern);
            });
        }
        // Always use JSON format for API responses
        args.push('--format', 'json');
        if (options.timeout) {
            args.push('--timeout', String(options.timeout));
        }
        if (options.maxFileSize) {
            args.push('--max-file-size', String(options.maxFileSize));
        }
        if (options.maxTotalSize) {
            args.push('--max-total-size', String(options.maxTotalSize));
        }
        if (options.verbose) {
            args.push('--verbose');
        }
        logger_1.default.info(`Running model scan on: ${resolvedPaths.join(', ')}`);
        // Track the scan
        telemetry_1.default.record('webui_api', {
            event: 'model_scan',
            pathCount: paths.length,
            hasBlacklist: options.blacklist?.length > 0,
            timeout: options.timeout,
            verbose: options.verbose,
        });
        // Run the scan
        const modelAudit = (0, child_process_2.spawn)('modelaudit', args);
        let stdout = '';
        let stderr = '';
        modelAudit.stdout.on('data', (data) => {
            stdout += data.toString();
        });
        modelAudit.stderr.on('data', (data) => {
            stderr += data.toString();
        });
        modelAudit.on('error', (error) => {
            logger_1.default.error(`Failed to start modelaudit: ${error.message}`);
            res.status(500).json({
                error: 'Failed to start model scan. Make sure Python and modelaudit are installed.',
            });
        });
        modelAudit.on('close', (code) => {
            // ModelAudit returns exit code 1 when it finds issues, which is expected
            if (code === 0 || code === 1) {
                try {
                    // Find JSON in the output (it might be mixed with other log messages)
                    const jsonMatch = stdout.match(/\{[\s\S]*\}/);
                    if (!jsonMatch) {
                        throw new Error('No JSON found in output');
                    }
                    // Parse JSON output
                    const scanResults = JSON.parse(jsonMatch[0]);
                    // Transform the results into our expected format
                    const transformedResults = {
                        path: resolvedPaths[0], // Primary resolved path
                        issues: scanResults.issues || [],
                        success: true,
                        scannedFiles: scanResults.files_scanned || resolvedPaths.length,
                        totalFiles: scanResults.files_total || resolvedPaths.length,
                        duration: scanResults.scan_duration || null,
                        rawOutput: stdout, // Always include raw output for debugging
                    };
                    res.json(transformedResults);
                }
                catch (parseError) {
                    logger_1.default.debug(`Failed to parse JSON from stdout: ${parseError}`);
                    logger_1.default.debug(`stdout: ${stdout}`);
                    logger_1.default.debug(`stderr: ${stderr}`);
                    // If JSON parsing fails, parse text output
                    const issues = [];
                    // Parse the log format output
                    const lines = stdout.split('\n');
                    lines.forEach((line) => {
                        // Parse lines like: "2025-06-08 20:46:58,090 - modelaudit.scanners - WARNING - [WARNING] (/path/to/file): Message"
                        const warningMatch = line.match(/\[WARNING\]\s*\(([^)]+)\):\s*(.+)/);
                        const errorMatch = line.match(/\[ERROR\]\s*\(([^)]+)\):\s*(.+)/);
                        const infoMatch = line.match(/\[INFO\]\s*\(([^)]+)\):\s*(.+)/);
                        if (warningMatch) {
                            issues.push({
                                severity: 'warning',
                                message: warningMatch[2],
                                location: warningMatch[1],
                            });
                        }
                        else if (errorMatch) {
                            issues.push({
                                severity: 'error',
                                message: errorMatch[2],
                                location: errorMatch[1],
                            });
                        }
                        else if (infoMatch) {
                            issues.push({
                                severity: 'info',
                                message: infoMatch[2],
                                location: infoMatch[1],
                            });
                        }
                        else if (line.includes(' - WARNING - ')) {
                            // Fallback for other warning formats
                            const parts = line.split(' - WARNING - ');
                            if (parts[1]) {
                                issues.push({
                                    severity: 'warning',
                                    message: parts[1],
                                });
                            }
                        }
                        else if (line.includes(' - ERROR - ')) {
                            // Fallback for other error formats
                            const parts = line.split(' - ERROR - ');
                            if (parts[1]) {
                                issues.push({
                                    severity: 'error',
                                    message: parts[1],
                                });
                            }
                        }
                    });
                    // Count scanned files from the output
                    const scannedFiles = lines.filter((line) => line.includes('Scanning file:') || line.includes('Scanning directory:')).length;
                    res.json({
                        path: resolvedPaths[0],
                        issues,
                        success: true,
                        scannedFiles: scannedFiles || resolvedPaths.length,
                        rawOutput: stdout,
                    });
                }
            }
            else {
                // Only treat codes other than 0 and 1 as actual errors
                logger_1.default.error(`Model scan failed with code ${code}: ${stderr}`);
                res.status(500).json({
                    error: `Model scan failed with exit code ${code}: ${stderr || stdout || 'Unknown error'}`,
                    code,
                });
            }
        });
    }
    catch (error) {
        logger_1.default.error(`Error in model scan: ${error}`);
        res.status(500).json({ error: String(error) });
    }
});
//# sourceMappingURL=modelAudit.js.map