import { BrowserView } from 'electrobun/bun'
import {
  checkForCompletedUpdate,
  getRunningAppVersion,
  startAppUpdate
} from './appupdate.js'
import {
  checkForDuplicateInstallations,
  removeDuplicateInstallations
} from './check-duplicate-installations.js'
import { setSidebarViewMenu } from './menu.js'
import { sendToRenderer } from './notify.js'
import { resizeSpotlightWindow } from './spotlight.js'
import {
  clearAuthSession,
  getAppSettings,
  getAuthSession,
  setAppSettings,
  setAuthSession
} from './store.js'
import {
  getMainWindow,
  getWindowState,
  handleWindowControl,
  openExternalUrl,
  openInternalUrl
} from './window.js'

export function createAppRpc() {
  const requestHandlers = {
    getOsInfo: async () => ({
      platform: process.platform
    }),
    getWindowState: async () => getWindowState(),
    windowControl: async ({ action }) => {
      handleWindowControl(action)
      return { ok: true }
    },
    openExternalUrl: async ({ url }) => {
      openExternalUrl(url)
      return { ok: true }
    },
    openInternalUrl: async ({ url }) => ({
      ok: openInternalUrl(url)
    }),
    getAuthSession: async () => getAuthSession(),
    setAuthSession: async ({ session }) => ({
      ok: await setAuthSession(session)
    }),
    clearAuthSession: async () => ({
      ok: await clearAuthSession()
    }),
    getAppSettings: async () => getAppSettings(),
    setAppSettings: async ({ settings }) => ({
      ok: await setAppSettings(settings)
    }),
    startAppUpdate: async ({ update }) => {
      const mainWindow = getMainWindow()
      const sendProgress = (payload) => {
        sendToRenderer('appUpdateProgress', {
          timestamp: new Date().toISOString(),
          ...payload
        })
      }

      // Updates can take several minutes; return immediately and report
      // progress via appUpdateProgress messages instead of blocking RPC.
      void startAppUpdate(mainWindow, update, sendProgress).catch((error) => {
        console.error('App update failed:', error)
      })
      return { ok: true }
    },
    resizeSpotlightWindow: async ({ height }) => ({
      ok: resizeSpotlightWindow(height)
    }),
    setSidebarViewMenu: async ({ sections }) => ({
      ok: setSidebarViewMenu(sections)
    }),
    checkAppUpdateResult: async () =>
      checkForCompletedUpdate(getMainWindow()),
    checkDuplicateInstallations: async () => checkForDuplicateInstallations(),
    removeDuplicateInstallations: async () => {
      // Removal waits on an admin/UAC prompt which can outlive the RPC
      // timeout; report the outcome via a push message instead.
      void removeDuplicateInstallations()
        .catch((error) => ({
          ok: false,
          error:
            error?.message || 'Failed to remove the duplicate installation.'
        }))
        .then((result) => {
          sendToRenderer('duplicateInstallationsRemoved', result)
        })
      return { ok: true }
    },
    getAppVersion: async () => getRunningAppVersion() || 'desktop',
    getAppEngine: async () => {
      const mainWindow = getMainWindow()
      const renderer = mainWindow?.renderer || 'native'
      return renderer === 'cef' ? 'chromium' : 'native'
    }
  }

  return BrowserView.defineRPC({
    maxRequestTime: 30000,
    handlers: {
      requests: requestHandlers,
      messages: {
        rendererRequest: ({ id, method, params }) => {
          const handler = requestHandlers[method]
          if (!handler) {
            sendToRenderer('rpcResponse', {
              id,
              success: false,
              error: `Unknown desktop RPC method: ${String(method)}`
            })
            return
          }

          void Promise.resolve()
            .then(() => handler(params || {}))
            .then((result) => {
              sendToRenderer('rpcResponse', {
                id,
                success: true,
                result
              })
            })
            .catch((error) => {
              sendToRenderer('rpcResponse', {
                id,
                success: false,
                error: error?.message || String(error)
              })
            })
        }
      }
    }
  })
}
