import React, { useEffect, useRef } from 'react'
import ReactDOM from 'react-dom'
import styled from '@emotion/styled'
import { Terminal } from 'xterm'
import { FitAddon } from 'xterm-addon-fit'
import { Shell } from 'blessing-skin-shell'
import 'xterm/css/xterm.css'
import Draggable from 'react-draggable'
import * as event from './event'
import AptCommand from './cli/AptCommand'
import ClosetCommand from './cli/ClosetCommand'
import DnfCommand from './cli/DnfCommand'
import PacmanCommand from './cli/PacmanCommand'
import RmCommand from './cli/RmCommand'
import * as breakpoints from '@/styles/breakpoints'

let launched = false

const TerminalContainer = styled.div`
  z-index: 1040;
  position: fixed;
  bottom: 7vh;
  user-select: none;

  .card-body {
    background-color: #000;
  }

  ${breakpoints.greaterThan(breakpoints.Breakpoint.xl)} {
    left: 25vw;
    width: 50vw;
    height: 50vh;
  }

  ${breakpoints.between(breakpoints.Breakpoint.md, breakpoints.Breakpoint.xl)} {
    left: 5vw;
    width: 90vw;
    height: 40vh;
  }

  ${breakpoints.lessThan(breakpoints.Breakpoint.md)} {
    left: 1vw;
    width: 98vw;
    height: 35vh;
  }
`

const TerminalWindow: React.FC<{ onClose(): void }> = (props) => {
  const mount = useRef<HTMLDivElement>(null)

  useEffect(() => {
    const el = mount.current
    if (!el) {
      return
    }

    const terminal = new Terminal()
    const fitAddon = new FitAddon()
    terminal.loadAddon(fitAddon)
    terminal.setOption(
      'fontFamily',
      'Monaco, Consolas, "Roboto Mono", "Noto Sans", "Droid Sans Mono"',
    )
    terminal.open(el)
    fitAddon.fit()

    const shell = new Shell(terminal)
    shell.addExternal(AptCommand.name, AptCommand)
    shell.addExternal('closet', ClosetCommand)
    shell.addExternal(DnfCommand.name, DnfCommand)
    shell.addExternal(PacmanCommand.name, PacmanCommand)
    shell.addExternal('rm', RmCommand)

    const unbindData = terminal.onData((e) => shell.input(e))
    const unbindKey = terminal.onKey((e) =>
      event.emit('terminalKeyPress', e.key),
    )
    launched = true

    return () => {
      unbindData.dispose()
      unbindKey.dispose()
      shell.free()
      fitAddon.dispose()
      terminal.dispose()
      launched = false
    }
  }, [])

  return (
    <Draggable handle=".card-header">
      <TerminalContainer className="card">
        <div className="card-header">
          <div className="d-flex justify-content-between">
            <h4 className="card-title mt-1">Blessing Skin Shell</h4>
            <button className="btn btn-default" onClick={props.onClose}>
              &times;
            </button>
          </div>
        </div>
        <div className="card-body p-2" ref={mount}></div>
      </TerminalContainer>
    </Draggable>
  )
}

export function launch() {
  if (launched) {
    return
  }

  const container = document.createElement('div')
  document.body.appendChild(container)

  const handleClose = () => {
    ReactDOM.unmountComponentAtNode(container)
    container.remove()
  }

  ReactDOM.render(<TerminalWindow onClose={handleClose} />, container)
}
