"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isElevated = isElevated;
exports.getSystemIncludePath = getSystemIncludePath;
exports.downloadFile = downloadFile;
exports.installTestlibFile = installTestlibFile;
exports.installTestlibFileElevated = installTestlibFileElevated;
exports.verifyTestlibInstallation = verifyTestlibInstallation;
exports.createBackup = createBackup;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const https_1 = __importDefault(require("https"));
const child_process_1 = require("child_process");
function isElevated() {
    try {
        // On Unix-like systems, check if running as root
        if (process.platform !== 'win32') {
            return process.getuid?.() === 0;
        }
        // On Windows, try to write to a system directory as a test
        const testPath = 'C:\\Windows\\System32\\test_admin.tmp';
        try {
            fs_1.default.writeFileSync(testPath, '');
            fs_1.default.unlinkSync(testPath);
            return true;
        }
        catch {
            return false;
        }
    }
    catch {
        return false;
    }
}
async function requestElevatedExecution(content, targetPath) {
    const isWindows = process.platform === 'win32';
    const tempFile = path_1.default.join(process.env['TEMP'] || process.env['TMP'] || '/tmp', `testlib_${Date.now()}.h`);
    // Write content to temporary file
    fs_1.default.writeFileSync(tempFile, content, 'utf-8');
    return new Promise((resolve, reject) => {
        let elevatedProcess;
        if (isWindows) {
            // Windows: Use PowerShell with elevated privileges
            const psScript = `
        Start-Process powershell -Verb RunAs -ArgumentList "-NoProfile -ExecutionPolicy Bypass -Command \\"Copy-Item '${tempFile}' '${targetPath}' -Force\\"" -Wait
      `;
            const scriptPath = path_1.default.join(process.env['TEMP'] || process.env['TMP'] || '/tmp', `install_testlib_${Date.now()}.ps1`);
            fs_1.default.writeFileSync(scriptPath, psScript, 'utf-8');
            elevatedProcess = (0, child_process_1.spawn)('powershell', [
                '-NoProfile',
                '-ExecutionPolicy',
                'Bypass',
                '-File',
                scriptPath,
            ]);
        }
        else {
            // Unix-like: Use sudo with pkexec fallback
            const commands = [
                ['pkexec', 'cp', tempFile, targetPath],
                ['sudo', '-S', 'cp', tempFile, targetPath],
            ];
            // Try pkexec first (graphical sudo), fallback to sudo
            const tryCommand = (cmdIndex) => {
                if (cmdIndex >= commands.length) {
                    reject(new Error('Failed to obtain elevated privileges. Please install pkexec or ensure sudo is configured.'));
                    return;
                }
                const [cmd, ...args] = commands[cmdIndex];
                elevatedProcess = (0, child_process_1.spawn)(cmd, args, { stdio: 'inherit' });
                elevatedProcess.on('error', () => {
                    // Command not found, try next
                    tryCommand(cmdIndex + 1);
                });
                elevatedProcess.on('close', code => {
                    // Clean up temp file
                    try {
                        fs_1.default.unlinkSync(tempFile);
                    }
                    catch {
                        // Ignore cleanup errors
                    }
                    if (code === 0) {
                        resolve();
                    }
                    else if (cmdIndex + 1 < commands.length) {
                        // Try next command
                        tryCommand(cmdIndex + 1);
                    }
                    else {
                        reject(new Error('Failed to copy file with elevated privileges. Operation cancelled or insufficient permissions.'));
                    }
                });
            };
            tryCommand(0);
            return;
        }
        elevatedProcess.on('close', code => {
            // Clean up temp files
            try {
                fs_1.default.unlinkSync(tempFile);
                if (isWindows) {
                    const scriptPath = path_1.default.join(process.env['TEMP'] || process.env['TMP'] || '/tmp', `install_testlib_${Date.now()}.ps1`);
                    if (fs_1.default.existsSync(scriptPath)) {
                        fs_1.default.unlinkSync(scriptPath);
                    }
                }
            }
            catch {
                // Ignore cleanup errors
            }
            if (code === 0) {
                resolve();
            }
            else {
                reject(new Error('Failed to copy file with elevated privileges. Operation cancelled or insufficient permissions.'));
            }
        });
        elevatedProcess.on('error', err => {
            reject(new Error(`Failed to request elevated privileges: ${err.message}`));
        });
    });
}
async function getSystemIncludePath() {
    return new Promise((resolve, reject) => {
        const gccProcess = (0, child_process_1.spawn)('g++', ['-v', '-E', '-x', 'c++', '-'], {
            stdio: ['pipe', 'pipe', 'pipe'],
        });
        let stderr = '';
        gccProcess.stderr.on('data', (data) => {
            stderr += data.toString();
        });
        gccProcess.on('close', () => {
            const lines = stderr.split('\n');
            let inSearchList = false;
            const includePaths = [];
            for (const line of lines) {
                if (line.includes('#include <...> search starts here:')) {
                    inSearchList = true;
                    continue;
                }
                if (line.includes('End of search list')) {
                    break;
                }
                if (inSearchList) {
                    const trimmed = line.trim();
                    if (trimmed && !trimmed.startsWith('(')) {
                        includePaths.push(trimmed);
                    }
                }
            }
            // Prefer system paths in order, exclude user-local paths
            const preferredPaths = [
                '/usr/local/include',
                '/usr/include',
                ...includePaths.filter(p => !p.includes('.local')),
            ];
            // Try to find a writable system include path
            for (const includePath of preferredPaths) {
                if (fs_1.default.existsSync(includePath)) {
                    try {
                        fs_1.default.accessSync(includePath, fs_1.default.constants.W_OK);
                        resolve(includePath);
                        return;
                    }
                    catch {
                        continue;
                    }
                }
            }
            // No writable system path found - require sudo/admin privileges
            const firstPath = preferredPaths[0] || '/usr/local/include';
            const isWindows = process.platform === 'win32';
            const errorMsg = isWindows
                ? `No write permission to ${firstPath}\n\nElevated privileges will be requested to install testlib.h`
                : `No write permission to ${firstPath}\n\nElevated privileges (sudo) will be requested to install testlib.h`;
            reject(new Error(errorMsg));
        });
        gccProcess.on('error', err => {
            reject(new Error(`Failed to detect include paths. g++ not found or not working:\n\t${err.message}\n\nPlease install g++ and try again.`));
        });
        gccProcess.stdin.end();
    });
}
function downloadFile(url) {
    return new Promise((resolve, reject) => {
        https_1.default
            .get(url, response => {
            if (response.statusCode === 302 || response.statusCode === 301) {
                const redirectUrl = response.headers.location;
                if (redirectUrl) {
                    downloadFile(redirectUrl).then(resolve).catch(reject);
                    return;
                }
            }
            if (response.statusCode !== 200) {
                reject(new Error(`Failed to download file. HTTP status: ${response.statusCode}`));
                return;
            }
            let data = '';
            response.on('data', (chunk) => {
                data += chunk.toString();
            });
            response.on('end', () => {
                resolve(data);
            });
        })
            .on('error', err => {
            reject(new Error(`Download failed: ${err.message}`));
        });
    });
}
function installTestlibFile(content, targetPath) {
    const targetDir = path_1.default.dirname(targetPath);
    // Check write permission on target directory
    try {
        fs_1.default.accessSync(targetDir, fs_1.default.constants.W_OK);
        // We have permission, write directly
        fs_1.default.writeFileSync(targetPath, content, 'utf-8');
    }
    catch (err) {
        // No permission, will need elevated access
        if (err.code === 'EACCES') {
            throw new Error('ELEVATED_REQUIRED');
        }
        throw err;
    }
}
async function installTestlibFileElevated(content, targetPath) {
    await requestElevatedExecution(content, targetPath);
}
async function verifyTestlibInstallation() {
    const testCode = `#include "testlib.h"\nint main() { return 0; }`;
    const testFile = path_1.default.join(process.cwd(), '.testlib_check.cpp');
    fs_1.default.writeFileSync(testFile, testCode, 'utf-8');
    await new Promise((resolve, reject) => {
        const compileProcess = (0, child_process_1.spawn)('g++', [
            testFile,
            '-o',
            testFile.replace('.cpp', ''),
            '-std=c++17',
        ]);
        let stderr = '';
        compileProcess.stderr.on('data', (data) => {
            stderr += data.toString();
        });
        compileProcess.on('close', code => {
            try {
                fs_1.default.unlinkSync(testFile);
                const execFile = testFile.replace('.cpp', '');
                if (fs_1.default.existsSync(execFile)) {
                    fs_1.default.unlinkSync(execFile);
                }
            }
            catch {
                // Ignore cleanup errors
            }
            if (code === 0) {
                resolve();
            }
            else {
                reject(new Error(`Verification failed. Compilation error:\n${stderr || 'Unknown error'}`));
            }
        });
        compileProcess.on('error', err => {
            reject(new Error(`Failed to run g++: ${err.message}`));
        });
    });
}
function createBackup(targetPath) {
    const backupPath = `${targetPath}.backup.${Date.now()}`;
    fs_1.default.copyFileSync(targetPath, backupPath);
    return backupPath;
}
//# sourceMappingURL=testlib-installer.js.map