// Single source of truth for the Electron IPC surface. Main process
// registers handlers keyed by the CHANNEL constants; preload exposes a
// typed `window.electronAPI` that mirrors the same shape. Renderer
// imports the type-only declarations via a d.ts published from preload.
//
// Rule: anything that the Rust side of Tauri used to do goes through
// here. If a call is not in this file it should not exist in the
// renderer.

export const CHANNELS = {
  // Screen-share — replaces Rust screen_sources + browser getDisplayMedia
  // coordination. Video still flows through Chromium's native pipeline
  // (LiveKit JS SDK calls getDisplayMedia); we only feed it source ids.
  SCREEN_GET_SOURCES: 'screen:get-sources',
  SCREEN_GET_THUMBNAIL: 'screen:get-thumbnail',
  /** Renderer-driven source selection: the picker modal calls this with
   *  the chosen sourceId BEFORE invoking getDisplayMedia. The main-process
   *  display-media handler then routes that source into the LiveKit track
   *  (instead of silently granting request.frame). Pass null to clear. */
  SCREEN_SET_PENDING_SOURCE: 'screen:set-pending-source',

  // System audio loopback — Implementation is renderer-driven under Electron.
  // Main provides the screen source id (AUDIO_LOOPBACK_RESOLVE_SOURCE); the
  // renderer then calls navigator.mediaDevices.getUserMedia with a
  // chromeMediaSourceId constraint to obtain the loopback MediaStream
  // directly. The legacy START/STOP channels are kept as named constants
  // for now to avoid breaking type imports but have no handlers — see
  // the renderer's lib/screenAudio.ts for the new flow.
  AUDIO_LOOPBACK_RESOLVE_SOURCE: 'audio:loopback:resolve-source',

  // Native WASAPI process-loopback path (Windows only). Implemented by
  // the @chatapp/audio-loopback-native napi-rs addon; main owns the
  // session and forwards PCM chunks to the renderer via the CHUNK event.
  // Captures every render session on the box *except* our own PID tree,
  // so peers in a video call don't hear themselves echoed back when the
  // sharer ticks "include system audio". Falls back to the renderer-
  // driven getUserMedia path on macOS/Linux or when the addon isn't
  // available (dev builds without `pnpm build:native`, packaged builds
  // missing the .node binary, etc.).
  AUDIO_LOOPBACK_START: 'audio:loopback:start',
  /** Window-share variant: capture audio of ONLY the picked window's
   *  process tree (INCLUDE_TARGET_PROCESS_TREE). Renderer derives the
   *  HWND from desktopCapturer's `window:<HWND>:0` source ids. */
  AUDIO_LOOPBACK_START_FOR_WINDOW: 'audio:loopback:start-for-window',
  AUDIO_LOOPBACK_STOP: 'audio:loopback:stop',
  AUDIO_LOOPBACK_CHUNK: 'audio:loopback:chunk',

  // Global hotkeys — replaces @tauri-apps/plugin-global-shortcut. Main
  // owns the registration; renderer listens to `shortcut:fired` events
  // for press and `shortcut:released` for PTT-style release.
  SHORTCUT_REGISTER: 'shortcut:register',
  SHORTCUT_UNREGISTER: 'shortcut:unregister',
  SHORTCUT_IS_REGISTERED: 'shortcut:is-registered',
  SHORTCUT_EVT_FIRED: 'shortcut:fired',
  SHORTCUT_EVT_RELEASED: 'shortcut:released',

  // OS notifications — replaces @tauri-apps/plugin-notification. Permission
  // is always granted on desktop Electron; we keep the surface symmetric
  // with the Tauri version so renderer code doesn't need to branch.
  NOTIFY_SHOW: 'notify:show',
  NOTIFY_PERMISSION: 'notify:permission',

  // Tray badge — replaces tauri emit('tray-unread-update'). Main owns the
  // Tray instance and overlays an unread count; renderer just pushes
  // the number.
  TRAY_UNREAD: 'tray:unread',

  // Secure store — replaces plugin-stronghold + custom file vault. Uses
  // Electron safeStorage (DPAPI/Keychain/libsecret) to seal per-user
  // blobs on disk. `secure-store:open` establishes a per-user handle;
  // subsequent calls use the stringified handle.
  SECURE_STORE_OPEN: 'secure-store:open',
  SECURE_STORE_GET: 'secure-store:get',
  SECURE_STORE_SET: 'secure-store:set',
  SECURE_STORE_REMOVE: 'secure-store:remove',
  SECURE_STORE_CLOSE: 'secure-store:close',

  // Filesystem (scoped to app local data dir) — replaces plugin-fs.
  // All paths are relative to appLocalDataDir; main rejects traversal.
  FS_READ: 'fs:read',
  FS_WRITE: 'fs:write',
  FS_EXISTS: 'fs:exists',
  FS_MKDIR: 'fs:mkdir',
  FS_RENAME: 'fs:rename',
  FS_REMOVE: 'fs:remove',
  FS_APP_LOCAL_DATA_DIR: 'fs:app-local-data-dir',

  // SQLite — replaces plugin-sql. The renderer gets a handle per DB file.
  SQL_LOAD: 'sql:load',
  SQL_EXECUTE: 'sql:execute',
  SQL_SELECT: 'sql:select',
  SQL_CLOSE: 'sql:close',

  // Auto-updater — replaces plugin-updater. electron-updater feed.
  UPDATER_CHECK: 'updater:check',
  UPDATER_DOWNLOAD_INSTALL: 'updater:download-install',
  UPDATER_EVT_PROGRESS: 'updater:progress',

  // Autostart — replaces @tauri-apps/plugin-autostart. Uses Electron's
  // built-in app.setLoginItemSettings() to manage OS login items (Windows
  // registry Run key, macOS LaunchAgent, Linux .desktop entry).
  AUTOSTART_IS_ENABLED: 'autostart:is-enabled',
  AUTOSTART_SET: 'autostart:set',

  // Window fullscreen — replaces Tauri's `appWindow.setFullscreen(...)`.
  // Used by the call cinema mode to flip the host BrowserWindow into real
  // OS fullscreen so the Windows taskbar / macOS menubar gets covered.
  WINDOW_SET_FULLSCREEN: 'window:set-fullscreen',
} as const;

// ---- Screen sources ------------------------------------------------------

export interface ScreenSource {
  /** Opaque source id. Feed unchanged into getDisplayMedia via the
   *  chromeMediaSourceId constraint when we want Chromium to capture it. */
  id: string;
  name: string;
  kind: 'screen' | 'window';
  /** Display index for monitors (0-based). null for windows. */
  displayId: number | null;
  /** Pre-fetched thumbnail (data URL). Cheap to get from desktopCapturer
   *  so we return it inline with the listing — avoids a second round-trip
   *  per source. */
  thumbnailDataUrl: string | null;
  /** App icon for windows (data URL); null when unavailable. */
  iconDataUrl: string | null;
}

// ---- Audio loopback ------------------------------------------------------

export interface AudioFrame {
  captureId: number;
  sampleRate: number;
  channels: number;
  /** Base64 of interleaved f32 LE stereo. Matches the old Tauri
   *  payload shape so the existing AudioWorklet doesn't change. */
  samplesBase64: string;
}

/** Payload shape of `AUDIO_LOOPBACK_CHUNK` events delivered from main
 *  to the renderer. `samples` is a Float32Array of interleaved f32
 *  stereo PCM at 48kHz — Electron's structured-clone marshals
 *  TypedArrays directly, so no base64 hop is needed (unlike the legacy
 *  Tauri channel). */
export interface AudioLoopbackChunk {
  captureId: number;
  samples: Float32Array;
}

/** Result of `AUDIO_LOOPBACK_START`. */
export interface AudioLoopbackStartResult {
  captureId: number;
}

// ---- Shortcuts -----------------------------------------------------------

export type ShortcutKind = 'press' | 'ptt';

export interface ShortcutRegisterArgs {
  /** Accelerator in Electron syntax (e.g. `CommandOrControl+Shift+M`,
   *  or a bare key code like `F13`). PTT uses a single raw key. */
  accelerator: string;
  /** Opaque id the renderer picked. Used in `shortcut:fired` events and
   *  for unregister. Scoping to a logical id (not the accelerator)
   *  means the same key can be re-bound without double-register. */
  id: string;
  kind: ShortcutKind;
}

export interface ShortcutEvent {
  id: string;
  /** Monotonic timestamp (ms since epoch) — useful for PTT to detect
   *  held-key repeats at the OS level. */
  ts: number;
}

// ---- Notifications -------------------------------------------------------

export interface NotifyArgs {
  title: string;
  body: string;
  /** Silent = no system sound. Renderer already owns its own ringtone
   *  layer, so most notifications are silent. */
  silent?: boolean;
}

// ---- Secure store --------------------------------------------------------

export interface SecureStoreOpenArgs {
  userId: string;
}

export interface SecureStoreHandle {
  handle: string;
  /** True if the platform's safeStorage is available (encrypted). False
   *  means the store falls back to plaintext-on-disk — the renderer
   *  should warn the user and avoid storing long-lived secrets. */
  encrypted: boolean;
}

// ---- Filesystem ----------------------------------------------------------

export type FsPath = string;

export interface FsWriteArgs {
  path: FsPath;
  /** Base64 of raw bytes. JSON IPC can't carry binary cleanly. */
  dataBase64: string;
}

export interface FsRenameArgs {
  from: FsPath;
  to: FsPath;
}

// ---- SQL -----------------------------------------------------------------

export interface SqlLoadArgs {
  /** DB filename (resolved under appLocalDataDir). Tauri's plugin-sql
   *  calls these `sqlite:<name>`; we strip the prefix on the main side. */
  name: string;
}

export interface SqlExecuteArgs {
  handle: string;
  query: string;
  bindings?: unknown[];
}

export interface SqlExecuteResult {
  rowsAffected: number;
  lastInsertId: number | null;
}

export interface SqlSelectArgs {
  handle: string;
  query: string;
  bindings?: unknown[];
}

export type SqlSelectResult = Record<string, unknown>[];

// ---- Updater -------------------------------------------------------------

export interface UpdateInfo {
  version: string;
  releaseNotes: string | null;
}

export interface UpdateCheckResult {
  available: boolean;
  info: UpdateInfo | null;
}

export interface UpdateProgress {
  percent: number;
  transferred: number;
  total: number;
}

// ---- Runtime marker ------------------------------------------------------

/** Value exposed on `window.electronAPI.platform`. Used by the renderer
 *  to keep the existing `isTauriRuntime()`-style branches but pointed at
 *  the new runtime. */
export const ELECTRON_RUNTIME_MARKER = 'electron-chatapp-v1' as const;
