import {
  app,
  clipboard,
  desktopCapturer,
  dialog,
  ipcMain,
  nativeImage,
  net,
  Notification,
  shell
} from 'electron';
import * as fs from 'fs';
import * as fsp from 'fs/promises';
import * as path from 'path';
import { fileURLToPath, pathToFileURL } from 'url';
import {
  getDesktopSettingsSnapshot,
  readDesktopSettings,
  updateDesktopSettings,
  type DesktopSettings
} from '../desktop-settings';
import { applyLocalApiSettings, getLocalApiSnapshot } from '../api';
import { getProvisionSecret, storeProvisionSecret } from '../api/provision-secret-store';
import {
  activateLinuxScreenShareAudioRouting,
  deactivateLinuxScreenShareAudioRouting,
  prepareLinuxScreenShareAudioRouting,
  startLinuxScreenShareMonitorCapture,
  stopLinuxScreenShareMonitorCapture
} from '../audio/linux-screen-share-routing';
import {
  checkForDesktopUpdates,
  configureDesktopUpdaterContext,
  getDesktopUpdateState,
  handleDesktopSettingsChanged,
  restartToApplyUpdate,
  readDesktopUpdateServerHealth,
  type DesktopUpdateServerContext
} from '../update/desktop-updater';
import { consumePendingDeepLink } from '../app/deep-links';
import { synchronizeAutoStartSetting } from '../app/auto-start';
import { getIdleState } from '../idle/idle-monitor';
import {
  getMainWindow,
  getWindowIconPath,
  updateCloseToTraySetting
} from '../window/create-window';
import {
  deleteSavedTheme,
  getSavedThemesPath,
  listSavedThemes,
  readSavedTheme,
  writeSavedTheme
} from '../theme-library';
import { getLocalPluginsPath, listLocalPluginManifests } from '../plugin-library';
import {
  eraseUserData,
  exportUserData,
  importUserData,
  openCurrentDataFolder
} from '../data-management';
import { listRunningProcessNames } from '../process-list';
import { detectActiveGame } from '../game-detection';
import { collectAppMetricsSnapshot } from '../app-metrics';
import { clearAllTokens } from '../api/auth-store';
import {
  assertPathUnderUserData,
  grantPluginReadRoot,
  resolveReadablePath
} from '../path-jail';

const DEFAULT_MIME_TYPE = 'application/octet-stream';
const MAX_ACTIVE_DESKTOP_NOTIFICATIONS = 20;
const activeDesktopNotifications = new Set<Notification>();
const desktopNotificationCleanups = new Map<Notification, () => void>();
const FILE_CLIPBOARD_FORMATS = [
  'x-special/gnome-copied-files',
  'text/uri-list',
  'public.file-url',
  'FileNameW'
] as const;

async function resolveUserDataFilePath(filePath: string): Promise<string | null> {
  return await resolveReadablePath(filePath);
}

async function resolveWritableUserDataFilePath(filePath: string): Promise<string | null> {
  try {
    return await assertPathUnderUserData(filePath);
  } catch {
    return null;
  }
}

const MIME_TYPES_BY_EXTENSION: Record<string, string> = {
  '.7z': 'application/x-7z-compressed',
  '.aac': 'audio/aac',
  '.avi': 'video/x-msvideo',
  '.bmp': 'image/bmp',
  '.csv': 'text/csv',
  '.doc': 'application/msword',
  '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  '.gif': 'image/gif',
  '.gz': 'application/gzip',
  '.heic': 'image/heic',
  '.jpeg': 'image/jpeg',
  '.jpg': 'image/jpeg',
  '.json': 'application/json',
  '.m4a': 'audio/mp4',
  '.md': 'text/markdown',
  '.mov': 'video/quicktime',
  '.mp3': 'audio/mpeg',
  '.mp4': 'video/mp4',
  '.ogg': 'audio/ogg',
  '.pdf': 'application/pdf',
  '.png': 'image/png',
  '.ppt': 'application/vnd.ms-powerpoint',
  '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  '.rar': 'application/vnd.rar',
  '.svg': 'image/svg+xml',
  '.tar': 'application/x-tar',
  '.txt': 'text/plain',
  '.wav': 'audio/wav',
  '.webm': 'video/webm',
  '.webp': 'image/webp',
  '.xls': 'application/vnd.ms-excel',
  '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  '.xml': 'application/xml',
  '.zip': 'application/zip'
};

interface ClipboardFilePayload {
  data: string;
  lastModified: number;
  mime: string;
  name: string;
  path?: string;
}

interface DesktopNotificationPayload {
  body: string;
  requestAttention?: boolean;
  title: string;
}

function resolveLinuxDisplayServer(): string {
  if (process.platform !== 'linux') {
    return 'N/A';
  }

  const ozonePlatform = app.commandLine.getSwitchValue('ozone-platform')
    .trim()
    .toLowerCase();

  if (ozonePlatform === 'wayland') {
    return 'Wayland';
  }

  if (ozonePlatform === 'x11') {
    return 'X11';
  }

  const ozonePlatformHint = app.commandLine.getSwitchValue('ozone-platform-hint')
    .trim()
    .toLowerCase();

  if (ozonePlatformHint === 'wayland') {
    return 'Wayland';
  }

  if (ozonePlatformHint === 'x11') {
    return 'X11';
  }

  const sessionType = String(process.env['XDG_SESSION_TYPE'] || '').trim()
    .toLowerCase();

  if (sessionType === 'wayland') {
    return 'Wayland';
  }

  if (sessionType === 'x11') {
    return 'X11';
  }

  if (String(process.env['WAYLAND_DISPLAY'] || '').trim().length > 0) {
    return 'Wayland';
  }

  if (String(process.env['DISPLAY'] || '').trim().length > 0) {
    return 'X11';
  }

  return 'Unknown (Linux)';
}

function isSupportedClipboardFileFormat(format: string): boolean {
  return FILE_CLIPBOARD_FORMATS.some(
    (supportedFormat) => supportedFormat.toLowerCase() === format.toLowerCase()
  );
}

function extractClipboardFilePaths(buffer: Buffer, format: string): string[] {
  const textVariants = new Set<string>();
  const utf8Text = buffer.toString('utf8').replace(/\0/g, '')
    .trim();

  if (utf8Text) {
    textVariants.add(utf8Text);
  }

  if (format.toLowerCase() === 'filenamew') {
    const utf16Text = buffer.toString('utf16le').replace(/\0/g, '\n')
      .trim();

    if (utf16Text) {
      textVariants.add(utf16Text);
    }
  }

  const filePaths = new Set<string>();

  for (const text of textVariants) {
    for (const filePath of parseClipboardFilePathText(text)) {
      filePaths.add(filePath);
    }
  }

  return [...filePaths];
}

function parseClipboardFilePathText(text: string): string[] {
  return text
    .split(/\r?\n/)
    .map((line) => line.trim())
    .filter(
      (line) =>
        !!line &&
        !line.startsWith('#') &&
        line.toLowerCase() !== 'copy' &&
        line.toLowerCase() !== 'cut'
    )
    .flatMap((line) => {
      if (line.startsWith('file://')) {
        try {
          return [fileURLToPath(line)];
        } catch {
          return [];
        }
      }

      return path.isAbsolute(line) ? [line] : [];
    });
}

function inferMimeType(filePath: string): string {
  return MIME_TYPES_BY_EXTENSION[path.extname(filePath).toLowerCase()] ?? DEFAULT_MIME_TYPE;
}

async function readClipboardFiles(): Promise<ClipboardFilePayload[]> {
  const formats = clipboard.availableFormats();
  const filePaths = new Set<string>();

  for (const format of formats) {
    if (!isSupportedClipboardFileFormat(format)) {
      continue;
    }

    try {
      const buffer = clipboard.readBuffer(format);

      for (const filePath of extractClipboardFilePaths(buffer, format)) {
        filePaths.add(filePath);
      }
    } catch {
      /* ignore unreadable clipboard formats */
    }
  }

  const files: ClipboardFilePayload[] = [];

  for (const filePath of filePaths) {
    try {
      const stats = await fsp.stat(filePath);

      if (!stats.isFile()) {
        continue;
      }

      const data = await fsp.readFile(filePath);

      files.push({
        data: data.toString('base64'),
        lastModified: Math.round(stats.mtimeMs),
        mime: inferMimeType(filePath),
        name: path.basename(filePath),
        path: filePath
      });
    } catch {
      /* ignore files that are no longer readable */
    }
  }

  return files;
}

export function setupSystemHandlers(): void {
  ipcMain.on('get-linux-display-server', (event) => {
    event.returnValue = resolveLinuxDisplayServer();
  });

  ipcMain.handle('open-external', async (_event, url: string) => {
    if (typeof url === 'string' && (url.startsWith('http://') || url.startsWith('https://'))) {
      await shell.openExternal(url);
      return true;
    }

    return false;
  });

  ipcMain.handle('consume-pending-deep-link', () => consumePendingDeepLink());

  ipcMain.handle('get-sources', async () => {
    try {
      const thumbnailSize = { width: 240, height: 150 };
      const [screenSources, windowSources] = await Promise.all([
        desktopCapturer.getSources({
          types: ['screen'],
          thumbnailSize
        }),
        desktopCapturer.getSources({
          types: ['window'],
          thumbnailSize,
          fetchWindowIcons: true
        })
      ]);
      const sources = [...screenSources, ...windowSources];
      const uniqueSources = new Map(sources.map((source) => [source.id, source]));

      return [...uniqueSources.values()].map((source) => ({
        id: source.id,
        name: source.name,
        thumbnail: source.thumbnail.toDataURL()
      }));
    } catch {
      // desktopCapturer.getSources fails on Wayland; return empty so the
      // renderer falls through to getDisplayMedia with the system picker.
      return [];
    }
  });

  ipcMain.handle('get-running-process-names', async () => await listRunningProcessNames());

  ipcMain.handle('get-active-game-candidate', async () => await detectActiveGame());

  ipcMain.handle('get-ignored-game-processes', () => {
    return readDesktopSettings().ignoredGameProcesses;
  });

  ipcMain.handle('set-ignored-game-processes', (_event, list: unknown) => {
    const snapshot = updateDesktopSettings({ ignoredGameProcesses: Array.isArray(list) ? list : [] });

    return snapshot.ignoredGameProcesses;
  });

  ipcMain.handle('prepare-linux-screen-share-audio-routing', async () => {
    return await prepareLinuxScreenShareAudioRouting();
  });

  ipcMain.handle('activate-linux-screen-share-audio-routing', async () => {
    return await activateLinuxScreenShareAudioRouting();
  });

  ipcMain.handle('deactivate-linux-screen-share-audio-routing', async () => {
    return await deactivateLinuxScreenShareAudioRouting();
  });

  ipcMain.handle('start-linux-screen-share-monitor-capture', async (event) => {
    return await startLinuxScreenShareMonitorCapture(event.sender);
  });

  ipcMain.handle('stop-linux-screen-share-monitor-capture', async (_event, captureId?: string) => {
    return await stopLinuxScreenShareMonitorCapture(captureId);
  });

  ipcMain.handle('get-app-metrics', () => collectAppMetricsSnapshot());

  ipcMain.handle('store-provision-secret', async (_event, homeUserId: string, secret: string) =>
    await storeProvisionSecret(homeUserId, secret)
  );

  ipcMain.handle('get-provision-secret', async (_event, homeUserId: string) =>
    await getProvisionSecret(homeUserId)
  );

  ipcMain.handle('get-app-data-path', () => app.getPath('userData'));
  ipcMain.handle('open-current-data-folder', async () => await openCurrentDataFolder());
  ipcMain.handle('export-user-data', async () => await exportUserData());
  ipcMain.handle('import-user-data', async () => await importUserData());
  ipcMain.handle('erase-user-data', async () => await eraseUserData());
  ipcMain.handle('get-saved-themes-path', async () => await getSavedThemesPath());
  ipcMain.handle('get-local-plugins-path', async () => await getLocalPluginsPath());
  ipcMain.handle('list-local-plugin-manifests', async () => await listLocalPluginManifests());
  ipcMain.handle('list-saved-themes', async () => await listSavedThemes());
  ipcMain.handle('read-saved-theme', async (_event, fileName: string) => await readSavedTheme(fileName));
  ipcMain.handle('write-saved-theme', async (_event, fileName: string, text: string) => {
    return await writeSavedTheme(fileName, text);
  });

  ipcMain.handle('delete-saved-theme', async (_event, fileName: string) => {
    return await deleteSavedTheme(fileName);
  });

  ipcMain.handle('get-desktop-settings', () => getDesktopSettingsSnapshot());

  ipcMain.handle('show-desktop-notification', async (_event, payload: DesktopNotificationPayload) => {
    const title = typeof payload?.title === 'string' ? payload.title.trim() : '';
    const body = typeof payload?.body === 'string' ? payload.body : '';
    const mainWindow = getMainWindow();
    const suppressSystemNotification = mainWindow?.isVisible() === true
      && !mainWindow.isMinimized()
      && mainWindow.isMaximized();

    if (!title) {
      return false;
    }

    if (!suppressSystemNotification && Notification.isSupported()) {
      try {
        const notification = new Notification({
          title,
          body,
          icon: getWindowIconPath(),
          silent: true
        });
        const cleanup = () => {
          notification.removeListener('click', handleClick);
          notification.removeListener('close', cleanup);
          notification.removeListener('failed', cleanup);
          activeDesktopNotifications.delete(notification);
          desktopNotificationCleanups.delete(notification);
        };
        const handleClick = () => {
          if (!mainWindow) {
            cleanup();
            return;
          }

          if (mainWindow.isMinimized()) {
            mainWindow.restore();
          }

          if (!mainWindow.isVisible()) {
            mainWindow.show();
          }

          mainWindow.focus();
          cleanup();
          notification.close();
        };

        notification.on('click', handleClick);
        notification.once('close', cleanup);
        notification.once('failed', cleanup);
        activeDesktopNotifications.add(notification);
        desktopNotificationCleanups.set(notification, cleanup);

        while (activeDesktopNotifications.size > MAX_ACTIVE_DESKTOP_NOTIFICATIONS) {
          const oldestNotification = activeDesktopNotifications.values().next().value;

          if (!oldestNotification) {
            break;
          }

          desktopNotificationCleanups.get(oldestNotification)?.();
          oldestNotification.close();
        }

        notification.show();
      } catch {
        // Ignore notification center failures and still attempt taskbar attention.
      }
    }

    if (payload?.requestAttention && mainWindow && (mainWindow.isMinimized() || !mainWindow.isFocused())) {
      mainWindow.flashFrame(true);
    }

    return true;
  });

  ipcMain.handle('request-window-attention', () => {
    const mainWindow = getMainWindow();

    if (!mainWindow || (!mainWindow.isMinimized() && mainWindow.isFocused())) {
      return false;
    }

    mainWindow.flashFrame(true);
    return true;
  });

  ipcMain.handle('clear-window-attention', () => {
    getMainWindow()?.flashFrame(false);
    return true;
  });

  ipcMain.handle('get-auto-update-state', () => getDesktopUpdateState());

  ipcMain.handle('get-auto-update-server-health', async (_event, serverUrl: string) => {
    return await readDesktopUpdateServerHealth(serverUrl);
  });

  ipcMain.handle('configure-auto-update-context', async (_event, context: Partial<DesktopUpdateServerContext>) => {
    return await configureDesktopUpdaterContext(context);
  });

  ipcMain.handle('check-for-app-updates', async () => {
    return await checkForDesktopUpdates();
  });

  ipcMain.handle('restart-to-apply-update', () => restartToApplyUpdate());

  ipcMain.handle('set-desktop-settings', async (_event, patch: Partial<DesktopSettings>) => {
    const snapshot = updateDesktopSettings(patch);

    if (Object.prototype.hasOwnProperty.call(patch, 'allowedSignalingServers')) {
      clearAllTokens();
    }

    await synchronizeAutoStartSetting(snapshot.autoStart);
    updateCloseToTraySetting(snapshot.closeToTray);
    await handleDesktopSettingsChanged();
    await applyLocalApiSettings();
    return snapshot;
  });

  ipcMain.handle('get-local-api-status', () => getLocalApiSnapshot());

  ipcMain.handle('open-local-api-docs', async () => {
    const snapshot = getLocalApiSnapshot();

    if (snapshot.status !== 'running' || !snapshot.baseUrl) {
      return { opened: false, reason: 'Local API is not running' };
    }

    if (!snapshot.scalarEnabled) {
      return { opened: false, reason: 'Scalar docs are disabled' };
    }

    await shell.openExternal(`${snapshot.baseUrl}/docs`);
    return { opened: true };
  });

  ipcMain.handle('open-docusaurus-docs', async () => {
    let snapshot = getLocalApiSnapshot();

    if (snapshot.status !== 'running' || !snapshot.baseUrl || !snapshot.docusaurusEnabled) {
      const currentSettings = getDesktopSettingsSnapshot();

      updateDesktopSettings({
        localApi: {
          ...currentSettings.localApi,
          enabled: true,
          docusaurusEnabled: true
        }
      });

      await applyLocalApiSettings();
      snapshot = getLocalApiSnapshot();
    }

    if (snapshot.status !== 'running' || !snapshot.baseUrl) {
      return { opened: false, reason: snapshot.error ?? 'Local documentation server is not running' };
    }

    if (!snapshot.docusaurusEnabled) {
      return { opened: false, reason: 'Docusaurus docs are disabled' };
    }

    await shell.openExternal(`${snapshot.baseUrl}/docusaurus/`);
    return { opened: true };
  });

  ipcMain.handle('relaunch-app', () => {
    app.relaunch();
    app.exit(0);
    return true;
  });

  ipcMain.handle('copy-file', async (_event, sourceFilePath: string, destinationFilePath: string) => {
    if (typeof sourceFilePath !== 'string' || !sourceFilePath.trim()) {
      return false;
    }

    if (typeof destinationFilePath !== 'string' || !destinationFilePath.trim()) {
      return false;
    }

    const scopedDestination = await resolveWritableUserDataFilePath(destinationFilePath);

    if (!scopedDestination) {
      return false;
    }

    try {
      const stats = await fsp.stat(sourceFilePath);

      if (!stats.isFile()) {
        return false;
      }

      await fsp.copyFile(sourceFilePath, scopedDestination);
      return true;
    } catch {
      return false;
    }
  });

  ipcMain.handle('file-exists', async (_event, filePath: string) => {
    const scopedPath = await resolveUserDataFilePath(filePath);

    if (!scopedPath) {
      return false;
    }

    try {
      await fsp.access(scopedPath, fs.constants.F_OK);
      return true;
    } catch {
      return false;
    }
  });

  ipcMain.handle('get-file-url', async (_event, filePath: string) => {
    const scopedPath = await resolveUserDataFilePath(filePath);

    if (!scopedPath) {
      return null;
    }

    try {
      await fsp.access(scopedPath, fs.constants.F_OK);
      return pathToFileURL(scopedPath).toString();
    } catch {
      return null;
    }
  });

  ipcMain.handle('read-file', async (_event, filePath: string) => {
    const scopedPath = await resolveUserDataFilePath(filePath);

    if (!scopedPath) {
      return null;
    }

    const data = await fsp.readFile(scopedPath);

    return data.toString('base64');
  });

  ipcMain.handle('read-file-chunk', async (_event, filePath: string, start: number, end: number) => {
    const scopedPath = await resolveUserDataFilePath(filePath);

    if (!scopedPath) {
      return null;
    }

    const fileHandle = await fsp.open(scopedPath, 'r');

    try {
      const safeStart = Math.max(0, Math.trunc(start));
      const safeEnd = Math.max(safeStart, Math.trunc(end));
      const buffer = Buffer.alloc(safeEnd - safeStart);
      const result = await fileHandle.read(buffer, 0, buffer.length, safeStart);

      return buffer.subarray(0, result.bytesRead).toString('base64');
    } finally {
      await fileHandle.close();
    }
  });

  ipcMain.handle('get-file-size', async (_event, filePath: string) => {
    const scopedPath = await resolveUserDataFilePath(filePath);

    if (!scopedPath) {
      return null;
    }

    const stats = await fsp.stat(scopedPath);

    return stats.size;
  });

  ipcMain.handle('read-clipboard-files', async () => {
    return await readClipboardFiles();
  });

  ipcMain.handle('grant-plugin-read-root', (_event, rootPath: string) => {
    grantPluginReadRoot(rootPath);

    return true;
  });

  ipcMain.handle('write-file', async (_event, filePath: string, base64Data: string) => {
    const scopedPath = await resolveWritableUserDataFilePath(filePath);

    if (!scopedPath) {
      return false;
    }

    const buffer = Buffer.from(base64Data, 'base64');

    await fsp.writeFile(scopedPath, buffer);
    return true;
  });

  ipcMain.handle('append-file', async (_event, filePath: string, base64Data: string) => {
    const scopedPath = await resolveWritableUserDataFilePath(filePath);

    if (!scopedPath) {
      return false;
    }

    const buffer = Buffer.from(base64Data, 'base64');

    await fsp.appendFile(scopedPath, buffer);
    return true;
  });

  ipcMain.handle('delete-file', async (_event, filePath: string) => {
    const scopedPath = await resolveWritableUserDataFilePath(filePath);

    if (!scopedPath) {
      return false;
    }

    try {
      await fsp.unlink(scopedPath);
      return true;
    } catch (error) {
      if ((error as { code?: string }).code === 'ENOENT') {
        return true;
      }

      throw error;
    }
  });

  ipcMain.handle('save-file-as', async (_event, defaultFileName: string, base64Data: string) => {
    const result = await dialog.showSaveDialog({
      defaultPath: defaultFileName
    });

    if (result.canceled || !result.filePath) {
      return { saved: false,
        cancelled: true };
    }

    const buffer = Buffer.from(base64Data, 'base64');

    await fsp.writeFile(result.filePath, buffer);

    return { saved: true,
      cancelled: false };
  });

  ipcMain.handle('save-existing-file-as', async (_event, sourceFilePath: string, defaultFileName: string) => {
    if (typeof sourceFilePath !== 'string' || !sourceFilePath.trim()) {
      return { saved: false,
        cancelled: false };
    }

    const scopedSourcePath = await resolveUserDataFilePath(sourceFilePath);

    if (!scopedSourcePath) {
      return { saved: false,
        cancelled: false };
    }

    const stats = await fsp.stat(scopedSourcePath);

    if (!stats.isFile()) {
      return { saved: false,
        cancelled: false };
    }

    const result = await dialog.showSaveDialog({
      defaultPath: defaultFileName || path.basename(scopedSourcePath)
    });

    if (result.canceled || !result.filePath) {
      return { saved: false,
        cancelled: true };
    }

    await fsp.copyFile(scopedSourcePath, result.filePath);

    return { saved: true,
      cancelled: false };
  });

  ipcMain.handle('open-file-path', async (_event, filePath: string) => {
    if (typeof filePath !== 'string' || !filePath.trim()) {
      return { opened: false,
        reason: 'missing-path' };
    }

    const scopedPath = await resolveUserDataFilePath(filePath);

    if (!scopedPath) {
      return { opened: false,
        reason: 'outside-app-data' };
    }

    try {
      const stats = await fsp.stat(scopedPath);

      if (!stats.isFile()) {
        return { opened: false,
          reason: 'not-a-file' };
      }

      const error = await shell.openPath(scopedPath);

      return error
        ? { opened: false,
          reason: error }
        : { opened: true };
    } catch (error) {
      return { opened: false,
        reason: error instanceof Error ? error.message : 'open-failed' };
    }
  });

  ipcMain.handle('ensure-dir', async (_event, dirPath: string) => {
    const scopedPath = await resolveWritableUserDataFilePath(dirPath);

    if (!scopedPath) {
      return false;
    }

    await fsp.mkdir(scopedPath, { recursive: true });
    return true;
  });

  ipcMain.handle('copy-image-to-clipboard', (_event, srcURL: string) => {
    if (typeof srcURL !== 'string' || !srcURL) {
      return false;
    }

    return new Promise<boolean>((resolve) => {
      const request = net.request(srcURL);

      request.on('response', (response) => {
        const chunks: Buffer[] = [];

        response.on('data', (chunk) => chunks.push(chunk));
        response.on('end', () => {
          const image = nativeImage.createFromBuffer(Buffer.concat(chunks));

          if (!image.isEmpty()) {
            clipboard.writeImage(image);
            resolve(true);
          } else {
            resolve(false);
          }
        });

        response.on('error', () => resolve(false));
      });

      request.on('error', () => resolve(false));
      request.end();
    });
  });

  ipcMain.handle('context-menu-command', (_event, command: string) => {
    const allowedCommands = [
      'cut',
      'copy',
      'paste',
      'selectAll'
    ] as const;

    if (!allowedCommands.includes(command as typeof allowedCommands[number])) {
      return;
    }

    const mainWindow = getMainWindow();
    const webContents = mainWindow?.webContents;

    if (!webContents) {
      return;
    }

    switch (command) {
      case 'cut':
        webContents.cut();
        break;
      case 'copy':
        webContents.copy();
        break;
      case 'paste':
        webContents.paste();
        break;
      case 'selectAll':
        webContents.selectAll();
        break;
    }
  });

  ipcMain.handle('get-idle-state', () => {
    return getIdleState();
  });
}
