const { app, BrowserWindow, ipcMain, dialog, shell } = require('electron');
const path = require('path');
const { spawn, spawnSync } = require('child_process');
const fs = require('fs');

let mainWindow;

function createWindow() {
  mainWindow = new BrowserWindow({
    width: 1200,
    height: 820,
    minWidth: 1000,
    minHeight: 700,
    icon: path.join(__dirname, 'docs', 'dekupai-logo.png'), // Custom app logo
    frame: false, // Sleek frameless design
    transparent: false, // Set to false to avoid rendering bugs on some Windows setups
    backgroundColor: '#0a0a0f', // Dark baseline background
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
      contextIsolation: true,
      nodeIntegration: false,
      webSecurity: false // Disabled to allow canvas pixel reading on local file:// assets for Auto-Trim
    }
  });

  mainWindow.loadFile(path.join(__dirname, 'index.html'));
  mainWindow.setMenu(null); // Disable default menu and browser shortcuts (F5, F11, Ctrl+F5) to act as a proper native application.

  // Open DevTools if running in dev (optional)
  // mainWindow.webContents.openDevTools();
}

app.whenReady().then(() => {
  createWindow();

  app.on('activate', function () {
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

app.on('window-all-closed', function () {
  if (process.platform !== 'darwin') app.quit();
});

let cachedSystemPython = null;

function getResourceRoot() {
  if (app.isPackaged) {
    const unpacked = path.join(process.resourcesPath, 'app.asar.unpacked');
    if (fs.existsSync(unpacked)) return unpacked;
    return process.resourcesPath;
  }
  return __dirname;
}

function getDataRoot() {
  return app.isPackaged ? app.getPath('userData') : __dirname;
}

function getBackendPath(...segments) {
  return path.join(getResourceRoot(), 'backend', ...segments);
}

function readRegistryValue(key, valueName) {
  try {
    const result = spawnSync('reg', ['query', key, '/v', valueName], {
      encoding: 'utf8',
      windowsHide: true,
      timeout: 5000,
    });
    if (result.status !== 0) return '';
    const match = result.stdout.match(new RegExp(`${valueName}\\s+REG_(?:EXPAND_)?SZ\\s+(.*)`, 'i'));
    return match ? match[1].trim() : '';
  } catch (_) {
    return '';
  }
}

function getSpawnEnv() {
  const env = { ...process.env };
  if (process.platform !== 'win32') return env;

  const pathEntries = new Set();
  const addPaths = (value) => {
    if (!value) return;
    value.split(';').forEach((entry) => {
      const trimmed = entry.trim();
      if (trimmed) pathEntries.add(trimmed);
    });
  };

  addPaths(process.env.PATH);
  addPaths(readRegistryValue('HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment', 'Path'));
  addPaths(readRegistryValue('HKCU\\Environment', 'Path'));

  const localAppData = process.env.LOCALAPPDATA
    || (process.env.USERPROFILE ? path.join(process.env.USERPROFILE, 'AppData', 'Local') : null);
  if (localAppData) {
    pathEntries.add(path.join(localAppData, 'Programs', 'Python', 'Launcher'));
    for (const version of ['312', '311', '310']) {
      pathEntries.add(path.join(localAppData, 'Programs', 'Python', `Python${version}`));
      pathEntries.add(path.join(localAppData, 'Programs', 'Python', `Python${version}`, 'Scripts'));
    }
  }

  if (process.env.ProgramFiles) {
    for (const version of ['312', '311', '310']) {
      pathEntries.add(path.join(process.env.ProgramFiles, `Python${version}`));
      pathEntries.add(path.join(process.env.ProgramFiles, `Python${version}`, 'Scripts'));
    }
  }

  env.PATH = [...pathEntries].join(';');
  return env;
}

function getWindowsPythonCandidates() {
  const candidates = [];
  const seen = new Set();
  const addCandidate = (command, args = []) => {
    const key = `${command}::${args.join(' ')}`;
    if (seen.has(key)) return;
    seen.add(key);
    candidates.push({ command, args });
  };

  const localAppData = process.env.LOCALAPPDATA
    || (process.env.USERPROFILE ? path.join(process.env.USERPROFILE, 'AppData', 'Local') : null);

  if (localAppData) {
    const pyLauncher = path.join(localAppData, 'Programs', 'Python', 'Launcher', 'py.exe');
    if (fs.existsSync(pyLauncher)) {
      for (const flag of ['-3.12', '-3.11', '-3.10', '-3']) {
        addCandidate(pyLauncher, [flag]);
      }
    }

    for (const version of ['312', '311', '310']) {
      const pythonExe = path.join(localAppData, 'Programs', 'Python', `Python${version}`, 'python.exe');
      if (fs.existsSync(pythonExe)) addCandidate(pythonExe, []);
    }
  }

  if (process.env.ProgramFiles) {
    for (const version of ['312', '311', '310']) {
      const pythonExe = path.join(process.env.ProgramFiles, `Python${version}`, 'python.exe');
      if (fs.existsSync(pythonExe)) addCandidate(pythonExe, []);
    }
  }

  addCandidate('py', ['-3.12']);
  addCandidate('py', ['-3.11']);
  addCandidate('py', ['-3.10']);
  addCandidate('py', ['-3']);
  addCandidate('python', []);

  return candidates;
}

function verifyPython(command, args, env) {
  try {
    const result = spawnSync(command, [...args, '--version'], {
      encoding: 'utf8',
      windowsHide: true,
      timeout: 6000,
      env,
    });
    return result.status === 0 && !result.error;
  } catch (_) {
    return false;
  }
}

function resolveSystemPython() {
  if (cachedSystemPython) return cachedSystemPython;

  const env = getSpawnEnv();
  const candidates = process.platform === 'win32'
    ? getWindowsPythonCandidates()
    : [
        { command: 'python3', args: [] },
        { command: 'python', args: [] },
      ];

  for (const candidate of candidates) {
    if (verifyPython(candidate.command, candidate.args, env)) {
      cachedSystemPython = candidate;
      console.log(`[Python Resolver] Selected: ${candidate.command} ${candidate.args.join(' ')}`);
      return cachedSystemPython;
    }
  }

  console.warn('[Python Resolver] No working Python found; falling back to "python".');
  cachedSystemPython = { command: 'python', args: [], unverified: true };
  return cachedSystemPython;
}

function spawnPython(command, args, options = {}) {
  return spawn(command, args, {
    shell: false,
    windowsHide: true,
    env: getSpawnEnv(),
    ...options,
  });
}

function attachProcessListeners(child, { onLine, onClose, onError }) {
  child.stdout.on('data', (data) => {
    const output = data.toString();
    for (const line of output.split('\n')) {
      if (line.trim()) onLine(line.trim());
    }
  });

  child.stderr.on('data', (data) => {
    const errStr = data.toString();
    for (const line of errStr.split('\n')) {
      if (line.trim()) onLine(`[ERROR] ${line.trim()}`);
    }
  });

  child.on('error', (err) => onError(err));
  child.on('close', (code) => onClose(code));
}

// Helper: Get Python Path
function getPythonPaths() {
  const isWindows = process.platform === 'win32';
  const venvPython = isWindows
    ? path.join(getDataRoot(), '.venv', 'Scripts', 'python.exe')
    : path.join(getDataRoot(), '.venv', 'bin', 'python');

  const systemPython = resolveSystemPython();
  const hasVenv = fs.existsSync(venvPython);

  return { venvPython, systemPython, hasVenv };
}

// IPC: Check Python Setup Status
ipcMain.handle('check-python-setup', async () => {
  const { hasVenv } = getPythonPaths();
  return { hasVenv };
});

// IPC: Run Setup
ipcMain.handle('run-python-setup', async (event) => {
  const { systemPython } = getPythonPaths();
  const setupScript = getBackendPath('setup.py');
  const dataDir = getDataRoot();

  return new Promise((resolve) => {
    const { command, args: pythonArgs } = systemPython;
    const spawnArgs = [...pythonArgs, setupScript, '--data-dir', dataDir];
    console.log(`[Main Process] Spawning setup: ${command} ${spawnArgs.join(' ')}`);

    let stderrData = '';
    let settled = false;
    const settle = (payload) => {
      if (settled) return;
      settled = true;
      resolve(payload);
    };

    const setupProcess = spawnPython(command, spawnArgs, { cwd: dataDir });

    attachProcessListeners(setupProcess, {
      onLine: (line) => {
        console.log(`[Setup Output] ${line}`);
        event.sender.send('setup-progress', line);
        if (line.startsWith('[ERROR]')) stderrData += `${line}\n`;
      },
      onError: (err) => {
        console.error(`[Setup Error] Failed to start process: ${err.message}`);
        settle({
          code: 1,
          error: `Python baslatilamadi: ${err.message}. Python 3.10-3.12 kurulu oldugundan emin olun.`,
        });
      },
      onClose: (code) => {
        console.log(`[Main Process] Setup completed with exit code ${code}`);
        settle({ code, error: stderrData });
      },
    });
  });
});

// IPC: Run Background Removal Process
ipcMain.handle('remove-background', async (event, { inputPath, outputPath }) => {
  const { venvPython, hasVenv } = getPythonPaths();
  
  if (!hasVenv) {
    return { success: false, error: 'Python virtual environment not set up. Please run setup first.' };
  }

  const processScript = getBackendPath('process.py');

  return new Promise((resolve) => {
    console.log(`[Main Process] Spawning background removal: ${venvPython} ${processScript}`);
    const args = ['--input', inputPath, '--output', outputPath];
    let stderrData = '';
    let settled = false;
    const settle = (payload) => {
      if (settled) return;
      settled = true;
      resolve(payload);
    };

    const bgProcess = spawnPython(venvPython, [processScript, ...args], { cwd: getDataRoot() });

    attachProcessListeners(bgProcess, {
      onLine: (line) => {
        console.log(`[Python Output] ${line}`);
        event.sender.send('process-progress', line);
        if (line.startsWith('[ERROR]')) stderrData += `${line}\n`;
      },
      onError: (err) => {
        settle({ success: false, error: `Python baslatilamadi: ${err.message}` });
      },
      onClose: (code) => {
        console.log(`[Main Process] Process completed with exit code ${code}`);
        if (code === 0) {
          settle({ success: true, outputPath });
        } else {
          settle({ success: false, error: stderrData || `Process failed with exit code ${code}` });
        }
      },
    });
  });
});

// IPC: Select Image File Dialog
ipcMain.handle('select-image', async () => {
  const result = await dialog.showOpenDialog(mainWindow, {
    properties: ['openFile'],
    filters: [
      { name: 'Images', extensions: ['jpg', 'jpeg', 'png', 'webp', 'bmp'] }
    ]
  });
  
  if (!result.canceled && result.filePaths.length > 0) {
    return result.filePaths[0];
  }
  return null;
});

// IPC: Get Temp Output File Path
ipcMain.handle('get-temp-path', async (event, fileName) => {
  const tempDir = app.getPath('temp');
  // Ensure unique name to avoid cache issues
  const uniqueName = `birefnet_${Date.now()}_${fileName}`;
  return path.join(tempDir, uniqueName);
});

// IPC: Export Image Dialog
ipcMain.handle('export-image', async (event, { base64Data, defaultName }) => {
  const result = await dialog.showSaveDialog(mainWindow, {
    defaultPath: defaultName || 'processed_image.png',
    filters: [
      { name: 'PNG Image', extensions: ['png'] },
      { name: 'JPEG Image', extensions: ['jpg', 'jpeg'] },
      { name: 'WebP Image', extensions: ['webp'] }
    ]
  });

  if (!result.canceled && result.filePath) {
    try {
      // Strip base64 headers if present
      const base64Content = base64Data.replace(/^data:image\/\w+;base64,/, "");
      fs.writeFileSync(result.filePath, base64Content, 'base64');
      return { success: true, filePath: result.filePath };
    } catch (err) {
      return { success: false, error: err.message };
    }
  }
  return { success: false, canceled: true };
});

// IPC: Show in File Explorer
ipcMain.handle('show-in-explorer', async (event, filePath) => {
  if (fs.existsSync(filePath)) {
    shell.showItemInFolder(filePath);
    return true;
  }
  return false;
});

// IPC: Frameless Window Controls
ipcMain.on('window-minimize', () => {
  if (mainWindow) mainWindow.minimize();
});

ipcMain.on('window-maximize', () => {
  if (mainWindow) {
    if (mainWindow.isMaximized()) {
      mainWindow.unmaximize();
    } else {
      mainWindow.maximize();
    }
  }
});

ipcMain.on('window-close', () => {
  if (mainWindow) mainWindow.close();
});
