import {
  defineComponent, onBeforeUnmount, ref, type PropType, watch,
} from 'vue'
import './interactive-window.scss'

interface SlotOptions {
  onMouseDown: (e: MouseEvent) => void
}

export default defineComponent({
  props: {
    initialHeight: {
      type: Number,
      default: 600,
    },
    initialLeft: {
      type: Number,
      default: 0,
    },
    initialTop: {
      type: Number,
      default: 0,
    },
    initialWidth: {
      type: Number,
      default: 600,
    },
    slot: {
      type: Function as PropType<(options: SlotOptions) => JSX.Element>,
      required: true,
    },
  },
  setup(props) {
    const left = ref(props.initialLeft)
    const top = ref(props.initialTop)
    const height = ref(props.initialHeight)
    const width = ref(props.initialWidth)
    const isSelected = ref(false)

    const selectWindow = () => {
      window.dispatchEvent(new Event('arkUiResizeableWindowSelect'))
      isSelected.value = true
    }

    let dragPrevX = 0
    let dragPrevY = 0
    let isResizing = false
    let resizeElement: 'top'|'bottom'|'left'|'right'|null = null

    const startResize = (e: MouseEvent, element: 'top'|'bottom'|'left'|'right') => {
      dragPrevX = e.clientX
      dragPrevY = e.clientY
      isResizing = true
      resizeElement = element
    }

    const doResize = (e: MouseEvent) => {
      if (!isResizing) return

      const diffX = e.clientX - dragPrevX
      const diffY = e.clientY - dragPrevY

      if (resizeElement === 'top') {
        if (height.value + diffY < 100) return
        top.value += diffY
        height.value -= diffY
      }

      if (resizeElement === 'left') {
        if (width.value + diffX < 100) return
        left.value += diffX
        width.value -= diffX
      }

      if (resizeElement === 'bottom') {
        if (height.value + diffY < 100) return
        height.value += diffY
      }
      if (resizeElement === 'right') {
        if (width.value + diffX < 100) return
        width.value += diffX
      }

      dragPrevX = e.clientX
      dragPrevY = e.clientY
    }

    let isMoving = false

    const startMove = (e: MouseEvent) => {
      selectWindow()
      dragPrevX = e.clientX
      dragPrevY = e.clientY
      isMoving = true
    }

    const doMove = (e: MouseEvent) => {
      if (!isMoving) return

      const diffX = e.clientX - dragPrevX
      const diffY = e.clientY - dragPrevY

      left.value += diffX
      top.value += diffY

      dragPrevX = e.clientX
      dragPrevY = e.clientY
    }

    const mouseMove = (e: MouseEvent) => {
      if (isResizing) doResize(e)
      if (isMoving) doMove(e)
    }

    const endMouseMove = () => {
      isResizing = false
      isMoving = false
    }

    const onSelectListener = () => {
      isSelected.value = false
    }

    window.addEventListener('arkUiResizeableWindowSelect', onSelectListener)
    window.addEventListener('mousemove', mouseMove)
    window.addEventListener('mouseup', endMouseMove)

    onBeforeUnmount(() => {
      window.removeEventListener('arkUiResizeableWindowSelect', onSelectListener)
      window.removeEventListener('mousemove', mouseMove)
      window.removeEventListener('mouseup', endMouseMove)
    })

    return () => {
      const style = `height: ${height.value}px; left: ${left.value}px; top: ${top.value}px; width: ${width.value}px`
      return (
        <div
          class={`ark-ui-resizeable-window ${isSelected.value ? 'is-selected' : ''}`}
          style={style}
          onMousedown={selectWindow}
        >
          <div class="ark-ui-resizeable-window-top-line" onMousedown={(e: MouseEvent) => startResize(e, 'top')}/>
          <div
            class="ark-ui-resizeable-window-middle-line"
            style={`height: calc(${height.value}px - 16px);`}
          >
            <div class="ark-ui-resizeable-window-left-line" onMousedown={(e: MouseEvent) => startResize(e, 'left')}/>
            <div
              class="ark-ui-resizeable-window-slot"
              style={`height: calc(${height.value}px - 16px); width: calc(${width.value}px - 16px);`}
            >
              { props.slot({ onMouseDown: startMove }) }
            </div>
            <div class="ark-ui-resizeable-window-right-line" onMousedown={(e: MouseEvent) => startResize(e, 'right')}/>
          </div>
          <div class="ark-ui-resizeable-window-bottom-line" onMousedown={(e: MouseEvent) => startResize(e, 'bottom')}/>
        </div>
      )
    }
  },
})
