// External dependencies
import fs from 'fs-extra'
import { cloneDeep } from 'lodash'

// Electron modules
import {
  app,
  Menu,
  Tray,
  dialog,
  clipboard,
  Notification,
  screen,
  nativeTheme
} from 'electron'

// Custom utilities and modules
import uploader from 'apis/app/uploader'
import db, { GalleryDB } from '~/main/apis/core/datastore'
import windowManager from 'apis/app/window/windowManager'
import { IPasteStyle, IWindowList } from '#/types/enum'
import pasteTemplate from '~/main/utils/pasteTemplate'
import pkg from 'root/package.json'
import { ensureFilePath, handleCopyUrl } from '~/main/utils/common'
import { T } from '~/main/i18n'
import { isMacOSVersionGreaterThanOrEqualTo } from '~/main/utils/getMacOSVersion'
import { buildPicBedListMenu } from '~/main/events/remotes/menu'
import clipboardPoll from '~/main/utils/clipboardPoll'
import picgo from '../../core/picgo'
import { uploadClipboardFiles } from '../uploader/apis'
import { configPaths } from '~/universal/utils/configPaths'

let contextMenu: Menu | null
let tray: Tray | null

export function setDockMenu () {
  const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
  const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
  const dockMenu = Menu.buildFromTemplate([
    {
      label: T('OPEN_MAIN_WINDOW'),
      click () {
        const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
        settingWindow!.show()
        settingWindow!.focus()
        if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
          windowManager.get(IWindowList.MINI_WINDOW)!.hide()
        }
      }
    },
    {
      label: T('START_WATCH_CLIPBOARD'),
      click () {
        db.set(configPaths.settings.isListeningClipboard, true)
        clipboardPoll.startListening()
        clipboardPoll.on('change', () => {
          picgo.log.info('clipboard changed')
          uploadClipboardFiles()
        })
        setDockMenu()
      },
      enabled: !isListeningClipboard
    },
    {
      label: T('STOP_WATCH_CLIPBOARD'),
      click () {
        db.set(configPaths.settings.isListeningClipboard, false)
        clipboardPoll.stopListening()
        clipboardPoll.removeAllListeners()
        setDockMenu()
      },
      enabled: isListeningClipboard
    }
  ])
  app.dock.setMenu(dockMenu)
}

export function createMenu () {
  const submenu = buildPicBedListMenu()
  const appMenu = Menu.buildFromTemplate([
    {
      label: 'PicList',
      submenu: [
        {
          label: T('OPEN_MAIN_WINDOW'),
          click () {
            const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
            const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
            settingWindow!.show()
            settingWindow!.focus()
            if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
              windowManager.get(IWindowList.MINI_WINDOW)!.hide()
            }
          }
        },
        {
          label: T('RELOAD_APP'),
          click () {
            app.relaunch()
            app.exit(0)
          }
        }
      ]
    },
    {
      label: T('CHOOSE_DEFAULT_PICBED'),
      type: 'submenu',
      // @ts-ignore
      submenu
    },
    {
      label: 'Edit',
      // @ts-ignore
      submenu: [
        // @ts-ignore
        { label: 'Undo', accelerator: 'CmdOrCtrl+Z', selector: 'undo:' },
        // @ts-ignore
        { label: 'Redo', accelerator: 'Shift+CmdOrCtrl+Z', selector: 'redo:' },
        { type: 'separator' },
        // @ts-ignore
        { label: 'Cut', accelerator: 'CmdOrCtrl+X', selector: 'cut:' },
        // @ts-ignore
        { label: 'Copy', accelerator: 'CmdOrCtrl+C', selector: 'copy:' },
        // @ts-ignore
        { label: 'Paste', accelerator: 'CmdOrCtrl+V', selector: 'paste:' },
        // @ts-ignore
        { label: 'Select All', accelerator: 'CmdOrCtrl+A', selector: 'selectAll:' }
      ]
    },
    {
      label: T('QUIT'),
      submenu: [
        {
          label: T('QUIT'),
          role: 'quit'
        }
      ]
    }
  ])
  Menu.setApplicationMenu(appMenu)
}

export function createContextMenu () {
  const ClipboardWatcher = clipboardPoll
  const isListeningClipboard = db.get(configPaths.settings.isListeningClipboard) || false
  if (process.platform === 'darwin' || process.platform === 'win32') {
    const submenu = buildPicBedListMenu()
    const template = [
      {
        label: T('OPEN_MAIN_WINDOW'),
        click () {
          const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
          const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
          settingWindow!.show()
          settingWindow!.focus()
          if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
            windowManager.get(IWindowList.MINI_WINDOW)!.hide()
          }
        }
      },
      {
        label: T('CHOOSE_DEFAULT_PICBED'),
        type: 'submenu',
        // @ts-ignore
        submenu
      },
      {
        label: T('START_WATCH_CLIPBOARD'),
        click () {
          db.set(configPaths.settings.isListeningClipboard, true)
          ClipboardWatcher.startListening()
          ClipboardWatcher.on('change', () => {
            picgo.log.info('clipboard changed')
            uploadClipboardFiles()
          })
          createContextMenu()
        },
        enabled: !isListeningClipboard
      },
      {
        label: T('STOP_WATCH_CLIPBOARD'),
        click () {
          db.set(configPaths.settings.isListeningClipboard, false)
          ClipboardWatcher.stopListening()
          ClipboardWatcher.removeAllListeners()
          createContextMenu()
        },
        enabled: isListeningClipboard
      },
      {
        label: T('RELOAD_APP'),
        click () {
          app.relaunch()
          app.exit(0)
        }
      },
      // @ts-ignore
      {
        role: 'quit',
        label: T('QUIT')
      }
    ] as any
    if (process.platform === 'win32') {
      template.splice(2, 0,
        {
          label: T('OPEN_MINI_WINDOW'),
          click () {
            const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
            miniWindow.removeAllListeners()
            if (db.get(configPaths.settings.miniWindowOntop)) {
              miniWindow.setAlwaysOnTop(true)
            }
            const { width, height } = screen.getPrimaryDisplay().workAreaSize
            const lastPosition = db.get(configPaths.settings.miniWindowPosition)
            if (lastPosition) {
              miniWindow.setPosition(lastPosition[0], lastPosition[1])
            } else {
              miniWindow.setPosition(width - 100, height - 100)
            }
            const setPositionFunc = () => {
              const position = miniWindow.getPosition()
              db.set(configPaths.settings.miniWindowPosition, position)
            }
            miniWindow.on('close', setPositionFunc)
            miniWindow.on('move', setPositionFunc)
            miniWindow.show()
            miniWindow.focus()
            const autoCloseMainWindow = db.get(configPaths.settings.autoCloseMainWindow) || false
            if (windowManager.has(IWindowList.SETTING_WINDOW) && autoCloseMainWindow) {
              windowManager.get(IWindowList.SETTING_WINDOW)!.hide()
            }
          }
        }
      )
    }
    contextMenu = Menu.buildFromTemplate(template)
  } else if (process.platform === 'linux') {
    // TODO 图床选择功能
    // 由于在Linux难以像在Mac和Windows上那样在点击时构造ContextMenu，
    // 暂时取消这个选单，避免引起和设置中启用的图床不一致

    // TODO 重启应用功能
    // 目前的实现无法正常工作

    contextMenu = Menu.buildFromTemplate([
      {
        label: T('OPEN_MAIN_WINDOW'),
        click () {
          const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
          const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
          settingWindow!.show()
          settingWindow!.focus()
          if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
            windowManager.get(IWindowList.MINI_WINDOW)!.hide()
          }
        }
      },
      {
        label: T('OPEN_MINI_WINDOW'),
        click () {
          const miniWindow = windowManager.get(IWindowList.MINI_WINDOW)!
          miniWindow.removeAllListeners()
          if (db.get(configPaths.settings.miniWindowOntop)) {
            miniWindow.setAlwaysOnTop(true)
          }
          const { width, height } = screen.getPrimaryDisplay().workAreaSize
          const lastPosition = db.get(configPaths.settings.miniWindowPosition)
          if (lastPosition) {
            miniWindow.setPosition(lastPosition[0], lastPosition[1])
          } else {
            miniWindow.setPosition(width - 100, height - 100)
          }
          const setPositionFunc = () => {
            const position = miniWindow.getPosition()
            db.set(configPaths.settings.miniWindowPosition, position)
          }
          miniWindow.on('close', setPositionFunc)
          miniWindow.on('move', setPositionFunc)
          miniWindow.show()
          miniWindow.focus()
          const autoCloseMainWindow = db.get(configPaths.settings.autoCloseMainWindow) || false
          if (windowManager.has(IWindowList.SETTING_WINDOW) && autoCloseMainWindow) {
            windowManager.get(IWindowList.SETTING_WINDOW)!.hide()
          }
        }
      },
      {
        label: T('START_WATCH_CLIPBOARD'),
        click () {
          db.set(configPaths.settings.isListeningClipboard, true)
          ClipboardWatcher.startListening()
          ClipboardWatcher.on('change', () => {
            picgo.log.info('clipboard changed')
            uploadClipboardFiles()
          })
          createContextMenu()
        },
        enabled: !isListeningClipboard
      },
      {
        label: T('STOP_WATCH_CLIPBOARD'),
        click () {
          db.set(configPaths.settings.isListeningClipboard, false)
          ClipboardWatcher.stopListening()
          ClipboardWatcher.removeAllListeners()
          createContextMenu()
        },
        enabled: isListeningClipboard
      },
      {
        label: T('ABOUT'),
        click () {
          dialog.showMessageBox({
            title: 'PicList',
            message: 'PicList',
            buttons: ['Ok'],
            detail: `Version: ${pkg.version}\nAuthor: Kuingsmile\nGithub: https://github.com/Kuingsmile/PicList`
          })
        }
      },
      // @ts-ignore
      {
        role: 'quit',
        label: T('QUIT')
      }
    ])
  }
}

const getTrayIcon = () => {
  if (process.platform === 'darwin') {
    const isMacOSGreaterThan11 = isMacOSVersionGreaterThanOrEqualTo('11')
    return isMacOSGreaterThan11 ? `${__static}/menubar-newdarwinTemplate.png` : `${__static}/menubar.png`
  } else {
    return `${__static}/menubar-nodarwin.png`
  }
}

export function createTray () {
  const menubarPic = getTrayIcon()
  tray = new Tray(menubarPic)
  // click事件在Mac和Windows上可以触发（在Ubuntu上无法触发，Unity不支持）
  if (process.platform === 'darwin' || process.platform === 'win32') {
    tray.on('right-click', () => {
      if (windowManager.has(IWindowList.TRAY_WINDOW)) {
        windowManager.get(IWindowList.TRAY_WINDOW)!.hide()
      }
      createContextMenu()
      tray!.popUpContextMenu(contextMenu!)
    })
    tray.on('click', (event, bounds) => {
      if (process.platform === 'darwin') {
        toggleWindow(bounds)
        setTimeout(async () => {
          const img = clipboard.readImage()
          const obj: ImgInfo[] = []
          if (!img.isEmpty()) {
            // 从剪贴板来的图片默认转为png
            // https://github.com/electron/electron/issues/9035
            const imgPath = clipboard.read('public.file-url')
            if (imgPath) {
              const decodePath = ensureFilePath(imgPath)
              if (decodePath === imgPath) {
                obj.push({
                  imgUrl: imgPath
                })
              } else {
                if (decodePath !== '') {
                  // 带有中文的路径，无法直接被img.src所使用，会被转义
                  const base64 = await fs.readFile(decodePath.replace('file://', ''), { encoding: 'base64' })
                  obj.push({
                    imgUrl: `data:image/png;base64,${base64}`
                  })
                }
              }
            } else {
              const imgUrl = img.toDataURL()
              obj.push({
                width: img.getSize().width,
                height: img.getSize().height,
                imgUrl
              })
            }
          }
          windowManager.get(IWindowList.TRAY_WINDOW)!.webContents.send('clipboardFiles', obj)
        }, 0)
      } else {
        if (windowManager.has(IWindowList.TRAY_WINDOW)) {
          windowManager.get(IWindowList.TRAY_WINDOW)!.hide()
        }
        const settingWindow = windowManager.get(IWindowList.SETTING_WINDOW)
        const autoCloseMiniWindow = db.get(configPaths.settings.autoCloseMiniWindow) || false
        settingWindow!.show()
        settingWindow!.focus()
        if (windowManager.has(IWindowList.MINI_WINDOW) && autoCloseMiniWindow) {
          windowManager.get(IWindowList.MINI_WINDOW)!.hide()
        }
      }
    })

    tray.on('drag-enter', () => {
      if (nativeTheme.shouldUseDarkColors) {
        tray!.setImage(`${__static}/upload-dark.png`)
      } else {
        tray!.setImage(`${__static}/upload.png`)
      }
    })

    tray.on('drag-end', () => {
      tray!.setImage(getTrayIcon())
    })

    // drop-files only be supported in macOS
    // so the tray window must be available
    tray.on('drop-files', async (event: Event, files: string[]) => {
      const pasteStyle = db.get(configPaths.settings.pasteStyle) || IPasteStyle.MARKDOWN
      const rawInput = cloneDeep(files)
      const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
      const imgs = await uploader
        .setWebContents(trayWindow.webContents)
        .upload(files)
      const deleteLocalFile = db.get(configPaths.settings.deleteLocalFile) || false
      if (imgs !== false) {
        const pasteText: string[] = []
        for (let i = 0; i < imgs.length; i++) {
          if (deleteLocalFile) {
            await fs.remove(rawInput[i])
          }
          pasteText.push(await (pasteTemplate(pasteStyle, imgs[i], db.get(configPaths.settings.customLink))))
          const isShowResultNotification = db.get(configPaths.settings.uploadResultNotification) === undefined ? true : !!db.get(configPaths.settings.uploadResultNotification)
          if (isShowResultNotification) {
            const notification = new Notification({
              title: T('UPLOAD_SUCCEED'),
              body: imgs[i].imgUrl!
              // icon: files[i]
            })
            setTimeout(() => {
              notification.show()
            }, i * 100)
          }
          await GalleryDB.getInstance().insert(imgs[i])
        }
        handleCopyUrl(pasteText.join('\n'))
        trayWindow.webContents.send('dragFiles', imgs)
      }
    })
    // toggleWindow()
  } else if (process.platform === 'linux') {
  // click事件在Ubuntu上无法触发，Unity不支持（在Mac和Windows上可以触发）
  // 需要使用 setContextMenu 设置菜单
    createContextMenu()
    tray!.setContextMenu(contextMenu)
  }
}

const toggleWindow = (bounds: IBounds) => {
  const trayWindow = windowManager.get(IWindowList.TRAY_WINDOW)!
  if (trayWindow.isVisible()) {
    trayWindow.hide()
  } else {
    trayWindow.setPosition(bounds.x - 98 + 11, bounds.y, false)
    trayWindow.webContents.send('updateFiles')
    trayWindow.show()
    trayWindow.focus()
  }
}
