import { useEffect, useRef, cloneElement, useMemo } from 'react'
import PropTypes from 'prop-types'
import { Popover, Typography } from 'antd'
import loglevel from 'loglevel'
import config from '../../../config'
const logger = loglevel.getLogger('ApiServerContext')
logger.setLevel(config.logLevel)

const MODIFIER_ALIASES = {
  cmd: 'meta',
  meta: 'meta',
  ctrl: 'control',
  control: 'control',
  alt: 'alt',
  option: 'alt',
  shift: 'shift'
}

function parseShortcut(shortcut) {
  return shortcut
    .toLowerCase()
    .split('+')
    .map((part) => MODIFIER_ALIASES[part] ?? part)
}

function getPressedKey(event) {
  if (
    event.key === 'Meta' ||
    event.key === 'Control' ||
    event.key === 'Alt' ||
    event.key === 'Shift'
  ) {
    return event.key.toLowerCase()
  }
  if (event.code) {
    const code = event.code.toLowerCase()
    if (code.startsWith('key')) {
      return code.slice(3)
    }
    return code
  }
  return null
}

const { Text } = Typography

const KeyboardShortcut = ({
  shortcut,
  children,
  hint,
  onTrigger,
  log = false
}) => {
  const childRef = useRef()
  const pressedKeysRef = useRef(new Set())
  const shortcutKeys = useMemo(() => parseShortcut(shortcut), [shortcut])

  useEffect(() => {
    const handleKeyDown = (event) => {
      const key = getPressedKey(event)
      if (key) {
        pressedKeysRef.current.add(key)
      }

      if (log) {
        logger.info('Key Down:', key, 'Pressed Keys:', [
          ...pressedKeysRef.current
        ])
      }

      if (
        shortcutKeys.length &&
        shortcutKeys.every((k) => pressedKeysRef.current.has(k))
      ) {
        if (typeof onTrigger === 'function') {
          onTrigger(event)
        }
        event.preventDefault()
      }
    }

    const handleKeyUp = (event) => {
      const key = getPressedKey(event)
      if (key) {
        pressedKeysRef.current.delete(key)
      }
    }

    window.addEventListener('keydown', handleKeyDown)
    window.addEventListener('keyup', handleKeyUp)

    return () => {
      window.removeEventListener('keydown', handleKeyDown)
      window.removeEventListener('keyup', handleKeyUp)
    }
  }, [shortcutKeys, onTrigger, log])

  const element = cloneElement(children, { ref: childRef })

  if (hint) {
    return (
      <Popover
        content={
          <Text keyboard className='keyboard-shortcut-tooltip'>
            {hint}
          </Text>
        }
        arrow={false}
      >
        {element}
      </Popover>
    )
  }
  return element
}

KeyboardShortcut.propTypes = {
  shortcut: PropTypes.string.isRequired, // e.g. 'cmd+shift+p'
  onTrigger: PropTypes.func.isRequired,
  children: PropTypes.element.isRequired,
  hint: PropTypes.string, // Optional, e.g. '⌘ ⇧ P'
  log: PropTypes.bool // Optional, e.g. true
}

export default KeyboardShortcut
