import { Menu, Tray } from 'electron'
import path from 'path'
import { isLinux, isWindows } from './Types/Platforms'
import { Store, StoreKeys } from './Store'
import { AppName, tray as str } from './Strings'
import { isDev } from './Utils/Utils'

const icon = path.join(__dirname, '/icon/Icon-256x256.png')

export interface TrayManager {
  shouldMinimizeToTray(): boolean
  createTrayIcon(): void
  destroyTrayIcon(): void
}

export function createTrayManager(window: Electron.BrowserWindow, store: Store): TrayManager {
  let tray: Tray | undefined
  let updateContextMenu: (() => void) | undefined

  function showWindow() {
    window.show()

    if (isLinux()) {
      /* On some versions of GNOME the window may not be on top when
      restored. */
      window.setAlwaysOnTop(true)
      window.focus()
      window.setAlwaysOnTop(false)
    }
  }

  return {
    shouldMinimizeToTray() {
      return store.get(StoreKeys.MinimizeToTray)
    },

    createTrayIcon() {
      tray = new Tray(icon)
      tray.setToolTip(AppName)

      if (isWindows()) {
        /* On Windows, right-clicking invokes the menu, as opposed to
        left-clicking for the other platforms. So we map left-clicking
        to the conventional action of showing the app. */
        tray.on('click', showWindow)
      }

      const SHOW_WINDOW_ID = 'SHOW_WINDOW'
      const HIDE_WINDOW_ID = 'HIDE_WINDOW'
      const trayContextMenu = Menu.buildFromTemplate([
        {
          id: SHOW_WINDOW_ID,
          label: str().show,
          click: showWindow,
        },
        {
          id: HIDE_WINDOW_ID,
          label: str().hide,
          click() {
            window.hide()
          },
        },
        {
          type: 'separator',
        },
        {
          role: 'quit',
          label: str().quit,
        },
      ])

      updateContextMenu = function updateContextMenu() {
        if (window.isVisible()) {
          trayContextMenu.getMenuItemById(SHOW_WINDOW_ID)!.visible = false
          trayContextMenu.getMenuItemById(HIDE_WINDOW_ID)!.visible = true
        } else {
          trayContextMenu.getMenuItemById(SHOW_WINDOW_ID)!.visible = true
          trayContextMenu.getMenuItemById(HIDE_WINDOW_ID)!.visible = false
        }

        tray!.setContextMenu(trayContextMenu)
      }
      updateContextMenu()

      window.on('hide', updateContextMenu)
      window.on('focus', updateContextMenu)
      window.on('blur', updateContextMenu)
    },

    destroyTrayIcon() {
      if (isDev()) {
        /** Check our state */
        if (!updateContextMenu) {
          throw new Error('updateContextMenu === undefined')
        }
        if (!tray) {
          throw new Error('tray === undefined')
        }
      }

      window.off('hide', updateContextMenu!)
      window.off('focus', updateContextMenu!)
      window.off('blur', updateContextMenu!)
      tray!.destroy()
      tray = undefined
      updateContextMenu = undefined
    },
  }
}
