import { contextBridge, ipcRenderer, type IpcRendererEvent } from 'electron'
import { electronAPI } from '@electron-toolkit/preload'
import type {
  DdevAddonRegistryEntry,
  DdevInstalledAddon,
  DdevProjectDetail,
  DdevProjectSummary,
  DdevSnapshot,
  EnvironmentUpdate,
  LogDataEvent,
  LogExitEvent,
  TerminalDataEvent,
  TerminalExitEvent
} from '../shared/types'

// Custom APIs for renderer
const api = {
  projects: {
    list: (): Promise<DdevProjectSummary[]> => ipcRenderer.invoke('projects:list'),
    describe: (name: string): Promise<DdevProjectDetail> =>
      ipcRenderer.invoke('projects:describe', name),
    start: (operationId: string, name: string): Promise<void> =>
      ipcRenderer.invoke('projects:start', operationId, name),
    stop: (operationId: string, name: string): Promise<void> =>
      ipcRenderer.invoke('projects:stop', operationId, name),
    restart: (operationId: string, name: string): Promise<void> =>
      ipcRenderer.invoke('projects:restart', operationId, name),
    delete: (operationId: string, name: string): Promise<void> =>
      ipcRenderer.invoke('projects:delete', operationId, name),
    updateEnvironment: (
      operationId: string,
      name: string,
      approot: string,
      updates: EnvironmentUpdate
    ): Promise<void> =>
      ipcRenderer.invoke('projects:updateEnvironment', operationId, name, approot, updates)
  },
  terminal: {
    cancel: (operationId: string): Promise<boolean> =>
      ipcRenderer.invoke('terminal:cancel', operationId),
    onData: (callback: (event: TerminalDataEvent) => void): (() => void) => {
      const listener = (_event: IpcRendererEvent, data: TerminalDataEvent): void => callback(data)
      ipcRenderer.on('terminal:data', listener)
      return () => ipcRenderer.removeListener('terminal:data', listener)
    },
    onExit: (callback: (event: TerminalExitEvent) => void): (() => void) => {
      const listener = (_event: IpcRendererEvent, data: TerminalExitEvent): void => callback(data)
      ipcRenderer.on('terminal:exit', listener)
      return () => ipcRenderer.removeListener('terminal:exit', listener)
    }
  },
  database: {
    listSnapshots: (name: string, approot: string): Promise<DdevSnapshot[]> =>
      ipcRenderer.invoke('database:listSnapshots', name, approot),
    createSnapshot: (operationId: string, approot: string, snapshotName?: string): Promise<void> =>
      ipcRenderer.invoke('database:createSnapshot', operationId, approot, snapshotName),
    restoreSnapshot: (operationId: string, approot: string, snapshotName: string): Promise<void> =>
      ipcRenderer.invoke('database:restoreSnapshot', operationId, approot, snapshotName),
    deleteSnapshot: (operationId: string, approot: string, snapshotName: string): Promise<void> =>
      ipcRenderer.invoke('database:deleteSnapshot', operationId, approot, snapshotName),
    importFile: (operationId: string, approot: string, filePath: string): Promise<void> =>
      ipcRenderer.invoke('database:importFile', operationId, approot, filePath),
    exportFile: (operationId: string, approot: string, filePath: string): Promise<void> =>
      ipcRenderer.invoke('database:exportFile', operationId, approot, filePath),
    pickImportFile: (): Promise<string | null> => ipcRenderer.invoke('database:pickImportFile'),
    pickExportPath: (defaultFileName: string): Promise<string | null> =>
      ipcRenderer.invoke('database:pickExportPath', defaultFileName)
  },
  addons: {
    listRegistry: (): Promise<DdevAddonRegistryEntry[]> =>
      ipcRenderer.invoke('addons:listRegistry'),
    listInstalled: (name: string): Promise<DdevInstalledAddon[]> =>
      ipcRenderer.invoke('addons:listInstalled', name),
    install: (operationId: string, name: string, addonRepo: string): Promise<void> =>
      ipcRenderer.invoke('addons:install', operationId, name, addonRepo),
    remove: (operationId: string, name: string, addonName: string): Promise<void> =>
      ipcRenderer.invoke('addons:remove', operationId, name, addonName)
  },
  logs: {
    start: (operationId: string, name: string, service: string): Promise<void> =>
      ipcRenderer.invoke('logs:start', operationId, name, service),
    onData: (callback: (event: LogDataEvent) => void): (() => void) => {
      const listener = (_event: IpcRendererEvent, data: LogDataEvent): void => callback(data)
      ipcRenderer.on('logs:data', listener)
      return () => ipcRenderer.removeListener('logs:data', listener)
    },
    onExit: (callback: (event: LogExitEvent) => void): (() => void) => {
      const listener = (_event: IpcRendererEvent, data: LogExitEvent): void => callback(data)
      ipcRenderer.on('logs:exit', listener)
      return () => ipcRenderer.removeListener('logs:exit', listener)
    }
  },
  create: {
    pickDirectory: (): Promise<string | null> => ipcRenderer.invoke('create:pickDirectory'),
    configure: (
      operationId: string,
      directory: string,
      projectName: string,
      projectType: string,
      docroot: string
    ): Promise<void> =>
      ipcRenderer.invoke(
        'create:configure',
        operationId,
        directory,
        projectName,
        projectType,
        docroot
      ),
    downloadWordpress: (operationId: string, directory: string, locale: string): Promise<void> =>
      ipcRenderer.invoke('create:downloadWordpress', operationId, directory, locale),
    setupWordpress: (
      operationId: string,
      directory: string,
      siteUrl: string,
      title: string,
      adminUser: string,
      adminPassword: string,
      adminEmail: string,
      multisite: 'none' | 'subdirectory' | 'subdomain'
    ): Promise<void> =>
      ipcRenderer.invoke(
        'create:setupWordpress',
        operationId,
        directory,
        siteUrl,
        title,
        adminUser,
        adminPassword,
        adminEmail,
        multisite
      )
  },
  zoom: {
    in: (): Promise<number> => ipcRenderer.invoke('window:zoomIn'),
    out: (): Promise<number> => ipcRenderer.invoke('window:zoomOut'),
    reset: (): Promise<number> => ipcRenderer.invoke('window:zoomReset')
  }
}

export type Api = typeof api

// Use `contextBridge` APIs to expose Electron APIs to
// renderer only if context isolation is enabled, otherwise
// just add to the DOM global.
if (process.contextIsolated) {
  try {
    contextBridge.exposeInMainWorld('electron', electronAPI)
    contextBridge.exposeInMainWorld('api', api)
  } catch (error) {
    console.error(error)
  }
} else {
  // @ts-ignore (define in dts)
  window.electron = electronAPI
  // @ts-ignore (define in dts)
  window.api = api
}
