/* mixone TS preload template (tsc compiles to preload.js, contextBridge injected) */
import { contextBridge, ipcRenderer } from 'electron'

interface WindowOpenPayload {
  url?: string
  width?: number
  height?: number
  title?: string
}

interface BrowserWindowHandle {
  id: number
}

/* These types match the contract in `src/mixone-ipc.d.ts`; preload cannot import d.ts.
 * Expressed as structural types here, the compiled preload.js remains plain JS,
 * satisfying contextBridge interface checks.
 */

interface FileFilter { name: string; extensions: string[] }
interface OpenFileOptions {
  title?: string
  defaultPath?: string
  properties?: Array<'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles'>
  filters?: FileFilter[]
}
interface OpenFileResult {
  filePaths: string[]
  canceled: boolean
  bookmarks?: string[]
}
interface SaveFileOptions { title?: string; defaultPath?: string; filters?: FileFilter[] }
interface SaveFileResult { filePath: string | null; canceled: boolean }
interface MessageBoxOptions {
  type?: 'none' | 'info' | 'error' | 'question' | 'warning'
  title?: string
  message: string
  detail?: string
  buttons?: string[]
  defaultId?: number
  cancelId?: number
}
interface MessageBoxResult { response: number; checkboxResponse: boolean; canceled: boolean }

interface MixoneDialogApi {
  openFile: (options?: OpenFileOptions) => Promise<OpenFileResult>
  saveFile: (options?: SaveFileOptions) => Promise<SaveFileResult>
  messageBox: (options: MessageBoxOptions) => Promise<MessageBoxResult>
}

interface ReadTextOptions { encoding?: BufferEncoding }
interface ReadTextResult { content: string; size: number }
interface WriteTextOptions { encoding?: BufferEncoding }
interface FsStats { size: number; isFile: boolean; isDirectory: boolean; mtime: number }
interface DirEntry { name: string; isFile: boolean; isDirectory: boolean; isSymbolicLink: boolean }
interface ReadDirResult { entries: DirEntry[]; error?: string }
interface MixoneFsApi {
  readText: (filePath: string, options?: ReadTextOptions) => Promise<ReadTextResult>
  writeText: (filePath: string, content: string, options?: WriteTextOptions) => Promise<{ bytesWritten: number }>
  exists: (filePath: string) => Promise<boolean>
  stat: (filePath: string) => Promise<FsStats>
  unlinkSafe: (filePath: string) => Promise<{ success: boolean }>
  readDir: (dirPath: string) => Promise<ReadDirResult>
  mkdir: (dirPath: string, options?: { recursive?: boolean }) => Promise<{ success: boolean; error?: string }>
  rename: (oldPath: string, newPath: string) => Promise<{ success: boolean; error?: string }>
  copyFile: (src: string, dest: string) => Promise<{ success: boolean; error?: string }>
  appendText: (filePath: string, content: string, options?: WriteTextOptions) => Promise<{ success: boolean; error?: string }>
  readJson: (filePath: string) => Promise<{ data: any; error: string | null }>
  writeJson: (filePath: string, data: any, options?: { space?: number }) => Promise<{ success: boolean; error?: string }>
}

interface ClipboardImageInfo { empty: boolean; size: { width: number; height: number } | null }
interface MixoneClipboardApi {
  readText: () => Promise<string>
  writeText: (text: string) => Promise<{ success: true }>
  readHtml: () => Promise<string>
  writeHtml: (html: string) => Promise<{ success: true }>
  readImage: () => Promise<ClipboardImageInfo>
  clear: () => Promise<{ success: true }>
}

interface MixoneShellApi {
  openExternal: (url: string, options?: { activate?: boolean }) => Promise<{ success: true }>
  showItemInFolder: (fullPath: string) => Promise<{ success: true }>
  openPath: (fullPath: string) => Promise<string>
  beep: () => Promise<{ success: true }>
}

interface AppInfoResult {
  name: string
  version: string
  electron: string
  node: string
  chrome: string
  platform: NodeJS.Platform
  cwd: string
}
interface MixoneAppApi {
  info: () => Promise<AppInfoResult>
  relaunch: () => Promise<{ success: true }>
  quit: () => Promise<{ success: true }>
}

interface MixoneBridge {
  platform: NodeJS.Platform
  version: string
  node: string
  chrome: string
  isDesktop: true
  window: {
    open: (payload: WindowOpenPayload) => Promise<BrowserWindowHandle>
    openModal: (payload: WindowOpenPayload) => Promise<BrowserWindowHandle>
    close: () => Promise<{ success: true }>
    minimize: () => Promise<{ success: true }>
    maximize: () => Promise<{ success: true | false }>
    isMaximized: () => Promise<{ maximized: boolean }>
  }
  dialog: MixoneDialogApi
  fs: MixoneFsApi
  clipboard: MixoneClipboardApi
  shell: MixoneShellApi
  app: MixoneAppApi
}

declare global {
  interface Window {
    {{bridgeGlobal}}: MixoneBridge
  }
}

const windowApi = {
  open: (payload: WindowOpenPayload) => ipcRenderer.invoke('window:open', payload),
  openModal: (payload: WindowOpenPayload) => ipcRenderer.invoke('window:open-modal', payload),
  close: () => ipcRenderer.invoke('window:close-current'),
  minimize: () => ipcRenderer.invoke('window:minimize-current'),
  maximize: () => ipcRenderer.invoke('window:maximize-current'),
  isMaximized: () => ipcRenderer.invoke('window:is-maximized')
} as const

const dialogApi: MixoneDialogApi = {
  openFile: (options) => ipcRenderer.invoke('mixone:dialog:open-file', options),
  saveFile: (options) => ipcRenderer.invoke('mixone:dialog:save-file', options),
  messageBox: (options) => ipcRenderer.invoke('mixone:dialog:message-box', options)
}

const fsApi: MixoneFsApi = {
  readText: (filePath, options) => ipcRenderer.invoke('mixone:fs:read-text', filePath, options),
  writeText: (filePath, content, options) => ipcRenderer.invoke('mixone:fs:write-text', filePath, content, options),
  exists: (filePath) => ipcRenderer.invoke('mixone:fs:exists', filePath),
  stat: (filePath) => ipcRenderer.invoke('mixone:fs:stat', filePath),
  unlinkSafe: (filePath) => ipcRenderer.invoke('mixone:fs:unlink-safe', filePath),
  readDir: (dirPath) => ipcRenderer.invoke('mixone:fs:read-dir', dirPath),
  mkdir: (dirPath, options) => ipcRenderer.invoke('mixone:fs:mkdir', dirPath, options),
  rename: (oldPath, newPath) => ipcRenderer.invoke('mixone:fs:rename', oldPath, newPath),
  copyFile: (src, dest) => ipcRenderer.invoke('mixone:fs:copy-file', src, dest),
  appendText: (filePath, content, options) => ipcRenderer.invoke('mixone:fs:append-text', filePath, content, options),
  readJson: (filePath) => ipcRenderer.invoke('mixone:fs:read-json', filePath),
  writeJson: (filePath, data, options) => ipcRenderer.invoke('mixone:fs:write-json', filePath, data, options)
}

const clipboardApi: MixoneClipboardApi = {
  readText: () => ipcRenderer.invoke('mixone:clipboard:read-text'),
  writeText: (text) => ipcRenderer.invoke('mixone:clipboard:write-text', text),
  readHtml: () => ipcRenderer.invoke('mixone:clipboard:read-html'),
  writeHtml: (html) => ipcRenderer.invoke('mixone:clipboard:write-html', html),
  readImage: () => ipcRenderer.invoke('mixone:clipboard:read-image'),
  clear: () => ipcRenderer.invoke('mixone:clipboard:clear')
}

const shellApi: MixoneShellApi = {
  openExternal: (url, options) => ipcRenderer.invoke('mixone:shell:open-external', url, options),
  showItemInFolder: (fullPath) => ipcRenderer.invoke('mixone:shell:show-item-in-folder', fullPath),
  openPath: (fullPath) => ipcRenderer.invoke('mixone:shell:open-path', fullPath),
  beep: () => ipcRenderer.invoke('mixone:shell:beep')
}

const appApi: MixoneAppApi = {
  info: () => ipcRenderer.invoke('mixone:app:info'),
  relaunch: () => ipcRenderer.invoke('mixone:app:relaunch'),
  quit: () => ipcRenderer.invoke('mixone:app:quit')
}

contextBridge.exposeInMainWorld('{{bridgeGlobal}}', {
  platform: process.platform as NodeJS.Platform,
  version: process.versions.electron,
  node: process.versions.node,
  chrome: process.versions.chrome,
  isDesktop: true as const,
  window: windowApi,
  dialog: dialogApi,
  fs: fsApi,
  clipboard: clipboardApi,
  shell: shellApi,
  app: appApi
})