import { ipcMain, BrowserWindow, app, shell } from 'electron';
import * as os from 'os';
import * as path from 'path';
import * as fs from 'fs';
import { exec, spawn } from 'child_process';
import axios from 'axios';
import { expandPath } from './file_utils';

// Helper to execute shell commands
const runExec = (cmd: string): Promise<{ success: boolean; stdout?: string; stderr?: string; error?: string }> => {
  return new Promise((resolve) => {
    exec(cmd, (error, stdout, stderr) => {
      resolve({
        success: !error,
        stdout: stdout.trim(),
        stderr: stderr.trim(),
        error: error ? error.message : undefined
      });
    });
  });
};

let recordingProcess: any = null;

export function registerSystemHandlers() {
  
  // 1. Window Control
  ipcMain.handle('native:window-control', async (event, { action, value }) => {
    const win = 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
  ipcMain.handle('native:set-wallpaper', async (event, { path: imagePath }) => {
    const cleanPath = expandPath(imagePath);
    if (!fs.existsSync(cleanPath)) return { success: false, error: 'Image file not found' };

    if (os.platform() === 'darwin') {
      const script = `tell application "System Events" to set picture of every desktop to "${cleanPath}"`;
      return await runExec(`osascript -e '${script}'`);
    } else if (os.platform() === 'linux') {
      // Gnome/Ubuntu default
      return await runExec(`gsettings set org.gnome.desktop.background picture-uri "file://${cleanPath}"`);
    }
    
    return { success: false, error: 'Platform not supported' };
  });

  // 3. Power Control
  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)
  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 shell.openExternal(url);
    return { success: true };
  });

  // 5. Manage Recording (Aperture Wrapper)
  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 = 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 = 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 = spawn(binPath, args);
        
        recordingProcess.on('error', (err: any) => {
            console.error('Recording error:', err);
            recordingProcess = null;
        });

        recordingProcess.on('exit', (code: any) => {
            console.log(`Recording exited with code ${code}`);
            recordingProcess = null;
        });

        return { success: true, pid: recordingProcess.pid };
      } catch (e: any) {
        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)
  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 = 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
  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 axios({
                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: any) {
            return { success: false, error: `Download failed: ${e.message}` };
        }
    } else if (source === 'file' && localPath) {
        const cleanLocal = 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 };
  });
}
