import type { MenuItemConstructorOptions } from 'electron'
import { Menu } from 'electron'

import { locales } from '../utils/locales'
import { configManager } from './ConfigManager'

class ContextMenu {
  public contextMenu(w: Electron.WebContents) {
    w.on('context-menu', (_event, properties) => {
      const template: MenuItemConstructorOptions[] = this.createEditMenuItems(properties)
      const filtered = template.filter((item) => item.visible !== false)
      if (filtered.length > 0) {
        let template = [...filtered, ...this.createInspectMenuItems(w)]
        const dictionarySuggestions = this.createDictionarySuggestions(properties, w)
        if (dictionarySuggestions.length > 0) {
          template = [
            ...dictionarySuggestions,
            { type: 'separator' },
            this.createSpellCheckMenuItem(properties, w),
            { type: 'separator' },
            ...template
          ]
        }
        const menu = Menu.buildFromTemplate(template)
        menu.popup()
      }
    })
  }

  private createInspectMenuItems(w: Electron.WebContents): MenuItemConstructorOptions[] {
    const locale = locales[configManager.getLanguage()]
    const { common } = locale.translation
    const template: MenuItemConstructorOptions[] = [
      {
        id: 'inspect',
        label: common.inspect,
        click: () => {
          w.toggleDevTools()
        },
        enabled: true
      }
    ]

    return template
  }

  private createEditMenuItems(properties: Electron.ContextMenuParams): MenuItemConstructorOptions[] {
    const locale = locales[configManager.getLanguage()]
    const { common } = locale.translation
    const hasText = properties.selectionText.trim().length > 0
    const can = (type: string) => properties.editFlags[`can${type}`] && hasText

    const template: MenuItemConstructorOptions[] = [
      {
        id: 'copy',
        label: common.copy,
        role: 'copy',
        enabled: can('Copy'),
        visible: properties.isEditable || hasText
      },
      {
        id: 'paste',
        label: common.paste,
        role: 'paste',
        enabled: properties.editFlags.canPaste,
        visible: properties.isEditable
      },
      {
        id: 'cut',
        label: common.cut,
        role: 'cut',
        enabled: can('Cut'),
        visible: properties.isEditable
      }
    ]

    // remove role from items that are not enabled
    // https://github.com/electron/electron/issues/13554
    template.forEach((item) => {
      if (item.enabled === false) {
        item.role = undefined
      }
    })

    return template
  }

  private createSpellCheckMenuItem(
    properties: Electron.ContextMenuParams,
    w: Electron.WebContents
  ): MenuItemConstructorOptions {
    const hasText = properties.selectionText.length > 0

    return {
      id: 'learnSpelling',
      label: '&Learn Spelling',
      visible: Boolean(properties.isEditable && hasText && properties.misspelledWord),
      click: () => {
        w.session.addWordToSpellCheckerDictionary(properties.misspelledWord)
      }
    }
  }

  private createDictionarySuggestions(
    properties: Electron.ContextMenuParams,
    w: Electron.WebContents
  ): MenuItemConstructorOptions[] {
    const hasText = properties.selectionText.length > 0

    if (!hasText || !properties.misspelledWord) {
      return []
    }

    if (properties.dictionarySuggestions.length === 0) {
      return [
        {
          id: 'dictionarySuggestions',
          label: 'No Guesses Found',
          visible: true,
          enabled: false
        }
      ]
    }

    return properties.dictionarySuggestions.map((suggestion) => ({
      id: 'dictionarySuggestions',
      label: suggestion,
      visible: Boolean(properties.isEditable && hasText && properties.misspelledWord),
      click: (menuItem: Electron.MenuItem) => {
        w.replaceMisspelling(menuItem.label)
      }
    }))
  }
}

export const contextMenu = new ContextMenu()
