"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.registerSystemHandlers = registerSystemHandlers;
const electron_1 = require("electron");
const os = __importStar(require("os"));
const path = __importStar(require("path"));
const fs = __importStar(require("fs"));
const child_process_1 = require("child_process");
const axios_1 = __importDefault(require("axios"));
const file_utils_1 = require("./file_utils");
// Helper to execute shell commands
const runExec = (cmd) => {
    return new Promise((resolve) => {
        (0, child_process_1.exec)(cmd, (error, stdout, stderr) => {
            resolve({
                success: !error,
                stdout: stdout.trim(),
                stderr: stderr.trim(),
                error: error ? error.message : undefined
            });
        });
    });
};
let recordingProcess = null;
function registerSystemHandlers() {
    // 1. Window Control
    electron_1.ipcMain.handle('native:window-control', async (event, { action, value }) => {
        const win = electron_1.BrowserWindow.fromWebContents(event.sender);
        if (!win)
            return { success: false, error: 'No window found' };
        switch (action) {
            case 'maximize':
                win.maximize();
                break;
            case 'unmaximize':
                win.unmaximize();
                break;
            case 'minimize':
                win.minimize();
                break;
            case 'restore':
                win.restore();
                break;
            case 'close':
                win.close();
                break;
            case 'devtools':
                if (value)
                    win.webContents.openDevTools();
                else
                    win.webContents.closeDevTools();
                break;
            case 'kiosk':
                win.setKiosk(!!value);
                break;
            case 'fullscreen':
                win.setFullScreen(!!value);
                break;
            case 'reload':
                win.reload();
                break;
            default: return { success: false, error: `Unknown action: ${action}` };
        }
        return { success: true };
    });
    // 2. Set Wallpaper
    // Supports local path OR URL download. URL images are saved to a stable cache dir
    // so macOS can reference them persistently after reboot.
    // display: 'all' (default) | 'primary' (built-in) | 'external' (projector/second screen)
    // url_external: optional second URL for the external display only.
    electron_1.ipcMain.handle('native:set-wallpaper', async (event, { path: imagePath, url, url_external, display = 'all', api_key, account_id }) => {
        // Cache dir: ~/Library/Caches/OSIT/wallpaper on macOS, ~/.cache/osit/wallpaper on Linux.
        // Using a stable path means macOS keeps the reference across reboots.
        const wallpaper_cache_dir = os.platform() === 'darwin'
            ? path.join(os.homedir(), 'Library', 'Caches', 'OSIT', 'wallpaper')
            : path.join(os.homedir(), '.cache', 'osit', 'wallpaper');
        async function download_wallpaper_image(image_url, basename) {
            if (!fs.existsSync(wallpaper_cache_dir)) {
                fs.mkdirSync(wallpaper_cache_dir, { recursive: true });
            }
            // Infer extension from URL path, fall back to .jpg
            let ext = '.jpg';
            try {
                const url_path = new URL(image_url).pathname;
                const inferred = path.extname(url_path).toLowerCase();
                if (['.jpg', '.jpeg', '.png', '.webp'].includes(inferred)) {
                    ext = inferred === '.jpeg' ? '.jpg' : inferred;
                }
            }
            catch { }
            const dest_path = path.join(wallpaper_cache_dir, basename + ext);
            const headers = {};
            if (api_key)
                headers['x-aether-api-key'] = api_key;
            if (account_id)
                headers['x-account-id'] = account_id;
            try {
                const response = await (0, axios_1.default)({ method: 'get', url: image_url, responseType: 'stream', headers });
                const writer = fs.createWriteStream(dest_path);
                response.data.pipe(writer);
                await new Promise((resolve, reject) => {
                    writer.on('finish', resolve);
                    writer.on('error', reject);
                });
                return { success: true, path: dest_path };
            }
            catch (e) {
                return { success: false, error: `Wallpaper download failed: ${e.message}` };
            }
        }
        // HARDENED: write AppleScript to a temp file, same pattern as native:run-osascript.
        // The old osascript -e approach breaks on paths with spaces or special characters.
        async function apply_mac_wallpaper(img_path, display_target) {
            const escaped = img_path.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
            let script;
            if (display_target === 'primary') {
                script = `tell application "System Events"\n\ttell desktop 1\n\t\tset picture to "${escaped}"\n\tend tell\nend tell`;
            }
            else if (display_target === 'external') {
                script = `tell application "System Events"\n\ttell desktop 2\n\t\tset picture to "${escaped}"\n\tend tell\nend tell`;
            }
            else {
                script = `tell application "System Events"\n\ttell every desktop\n\t\tset picture to "${escaped}"\n\tend tell\nend tell`;
            }
            const script_path = path.join(os.tmpdir(), `ae_wallpaper_${Date.now()}.scpt`);
            fs.writeFileSync(script_path, script, 'utf-8');
            try {
                return await runExec(`osascript "${script_path}"`);
            }
            finally {
                try {
                    fs.unlinkSync(script_path);
                }
                catch { }
            }
        }
        if (os.platform() === 'darwin') {
            // Resolve primary image path
            let primary_path = null;
            if (imagePath) {
                const clean = (0, file_utils_1.expandPath)(imagePath);
                if (!fs.existsSync(clean))
                    return { success: false, error: 'Image file not found' };
                primary_path = clean;
            }
            else if (url) {
                const result = await download_wallpaper_image(url, 'wallpaper_primary');
                if (!result.success || !result.path)
                    return { success: false, error: result.error };
                primary_path = result.path;
            }
            if (!primary_path)
                return { success: false, error: 'No image source provided' };
            if (url_external) {
                // Different images for each display: set primary display first, then external
                const primary_result = await apply_mac_wallpaper(primary_path, 'primary');
                if (!primary_result.success)
                    return primary_result;
                const ext_result = await download_wallpaper_image(url_external, 'wallpaper_external');
                const ext_path = ext_result.success && ext_result.path ? ext_result.path : primary_path;
                return await apply_mac_wallpaper(ext_path, 'external');
            }
            else {
                return await apply_mac_wallpaper(primary_path, display);
            }
        }
        if (os.platform() === 'linux') {
            let img_path = imagePath ? (0, file_utils_1.expandPath)(imagePath) : null;
            if (!img_path && url) {
                const result = await download_wallpaper_image(url, 'wallpaper_primary');
                if (!result.success || !result.path)
                    return { success: false, error: result.error };
                img_path = result.path;
            }
            if (!img_path)
                return { success: false, error: 'No image source provided' };
            if (!fs.existsSync(img_path))
                return { success: false, error: 'Image file not found' };
            return await runExec(`gsettings set org.gnome.desktop.background picture-uri "file://${img_path}"`);
        }
        return { success: false, error: 'Platform not supported' };
    });
    // 3. Power Control
    electron_1.ipcMain.handle('native:power-control', async (event, { action }) => {
        let cmd = '';
        const isMac = os.platform() === 'darwin';
        const isLinux = os.platform() === 'linux';
        if (action === 'shutdown') {
            if (isMac)
                cmd = 'shutdown -h now'; // Requires sudo/admin usually
            if (isLinux)
                cmd = 'shutdown -h now';
        }
        else if (action === 'reboot') {
            if (isMac)
                cmd = 'shutdown -r now';
            if (isLinux)
                cmd = 'reboot';
        }
        else if (action === 'sleep') {
            if (isMac)
                cmd = 'pmset sleepnow';
            if (isLinux)
                cmd = 'systemctl suspend';
        }
        if (!cmd)
            return { success: false, error: 'Action not supported' };
        // NOTE: These commands often require root. 
        // For a kiosk, you might configure sudoers to allow this specific command without password.
        return await runExec(cmd);
    });
    // 4. Open External (Browser)
    electron_1.ipcMain.handle('native:open-external', async (event, { url, app: appName }) => {
        if (appName === 'chrome') {
            if (os.platform() === 'darwin') {
                return await runExec(`open -a "Google Chrome" "${url}"`);
            }
            else if (os.platform() === 'linux') {
                return await runExec(`google-chrome "${url}"`);
            }
        }
        else if (appName === 'firefox') {
            if (os.platform() === 'darwin') {
                return await runExec(`open -a "Firefox" "${url}"`);
            }
            else if (os.platform() === 'linux') {
                return await runExec(`firefox "${url}"`);
            }
        }
        // Default system handler
        await electron_1.shell.openExternal(url);
        return { success: true };
    });
    // 5. Manage Recording (Aperture Wrapper)
    electron_1.ipcMain.handle('native:manage-recording', async (event, { action, options }) => {
        if (os.platform() !== 'darwin')
            return { success: false, error: 'Recording only supported on macOS' };
        // Path to bundled aperture binary
        // In dev: ./resources/bin/aperture
        // In prod: process.resourcesPath/bin/aperture
        const binPath = electron_1.app.isPackaged
            ? path.join(process.resourcesPath, 'bin', 'aperture')
            : path.join(__dirname, '../../resources/bin/aperture'); // Adjust based on structure
        if (action === 'start') {
            if (recordingProcess)
                return { success: false, error: 'Recording already in progress' };
            const { fps = 30, audioDeviceId, output } = options || {};
            const cleanOutput = (0, file_utils_1.expandPath)(output || '~/tmp/recording.mp4');
            const args = ['run', '--fps', fps, '--output', cleanOutput];
            if (audioDeviceId)
                args.push('--audio-device-id', audioDeviceId);
            // Spawn process
            // Note: aperture is a CLI tool. We might need 'aperture' node package or the binary.
            // Assuming binary usage here.
            try {
                console.log(`Starting recording: ${binPath} ${args.join(' ')}`);
                recordingProcess = (0, child_process_1.spawn)(binPath, args);
                recordingProcess.on('error', (err) => {
                    console.error('Recording error:', err);
                    recordingProcess = null;
                });
                recordingProcess.on('exit', (code) => {
                    console.log(`Recording exited with code ${code}`);
                    recordingProcess = null;
                });
                return { success: true, pid: recordingProcess.pid };
            }
            catch (e) {
                return { success: false, error: e.message };
            }
        }
        else if (action === 'stop') {
            if (!recordingProcess)
                return { success: false, error: 'No recording in progress' };
            recordingProcess.kill('SIGINT'); // Send interrupt to stop cleanly
            recordingProcess = null;
            return { success: true };
        }
        else if (action === 'status') {
            return { success: true, isRecording: !!recordingProcess };
        }
        return { success: false, error: 'Unknown action' };
    });
    // 6. Set Display Layout (Displayplacer)
    electron_1.ipcMain.handle('native:set-display-layout', async (event, { mode, configStr }) => {
        if (os.platform() !== 'darwin')
            return { success: false, error: 'Display control only supported on macOS' };
        const binPath = electron_1.app.isPackaged
            ? path.join(process.resourcesPath, 'bin', 'displayplacer')
            : path.join(__dirname, '../../resources/bin/displayplacer');
        let cmd = '';
        if (mode === 'mirror') {
            // This usually requires querying current IDs, which is complex.
            // If configStr is provided (output of 'displayplacer list'), use it.
            if (configStr) {
                cmd = `"${binPath}" ${configStr}`;
            }
            else {
                return { success: false, error: 'Config string required for now' };
            }
        }
        else if (mode === 'extend') {
            if (configStr) {
                cmd = `"${binPath}" ${configStr}`;
            }
        }
        if (cmd) {
            return await runExec(cmd);
        }
        return { success: false, error: 'Invalid mode or missing config' };
    });
    // 7. Update App
    electron_1.ipcMain.handle('native:update-app', async (event, { source, url, path: localPath }) => {
        // 1. Determine Source File
        let updateFile = '';
        const tempDir = os.tmpdir();
        const destName = 'update_package.zip'; // Or .app, .AppImage
        const destPath = path.join(tempDir, destName);
        if (source === 'url' && url) {
            // Download
            try {
                const response = await (0, axios_1.default)({
                    method: 'get',
                    url: url,
                    responseType: 'stream'
                });
                const writer = fs.createWriteStream(destPath);
                response.data.pipe(writer);
                await new Promise((resolve, reject) => {
                    writer.on('finish', () => resolve(true));
                    writer.on('error', reject);
                });
                updateFile = destPath;
            }
            catch (e) {
                return { success: false, error: `Download failed: ${e.message}` };
            }
        }
        else if (source === 'file' && localPath) {
            const cleanLocal = (0, file_utils_1.expandPath)(localPath);
            if (fs.existsSync(cleanLocal)) {
                updateFile = cleanLocal;
            }
            else {
                return { success: false, error: 'Local update file not found' };
            }
        }
        if (!updateFile)
            return { success: false, error: 'No update source provided' };
        // 2. Install Logic (Stub)
        // Real implementation depends on OS and packaging format.
        // macOS: Mount DMG, copy .app to /Applications? Or Unzip .app?
        // Linux: chmod +x AppImage and move?
        console.log(`Ready to install update from: ${updateFile}`);
        // For now, just return success so the UI knows we "downloaded" it.
        return { success: true, message: 'Update downloaded/located. Installation logic requires packaging specifics.', downloadedPath: updateFile };
    });
}
//# sourceMappingURL=system_handlers.js.map