import {
  defineComponent,
  onMounted,
  ref,
  toRefs,
  VNode,
  watch,
  PropType
} from 'vue'
import classnames from 'classnames'
import { BufferBlock, Block } from '@/components/process-bar/block'
import { useDrag } from '@/hooks/index'
import { on, toFixed, noop } from '@/utils/index'
import { Tooltip } from 'ant-design-vue'
import './index.less'

const prefix = 'progress'

interface Slots {
  prefix?: () => VNode
  suffix?: () => VNode
}

export const ProgressBar = defineComponent({
  name: 'ProgressBar',
  props: {
    canDrage: {
      type: Boolean as PropType<boolean>,
      required: true
    },
    showTooltip: {
      type: Boolean as PropType<boolean>,
      default: true
    },
    current: {
      type: Number as PropType<number>,
      default: 0
    },
    draging: {
      type: Boolean as PropType<boolean>,
      default: false
    },
    block: {
      type: Array as PropType<Block[]>,
      default: []
    },
    onChange: {
      type: Function as PropType<(x: number, w: number) => void>,
      default: noop
    },
    onCurrent: {
      type: Function as PropType<(v: number) => void>,
      default: noop
    }
  },
  emits: ['update:draging'],
  setup(props, context) {
    const {
      canDrage,
      onChange,
      draging,
      block,
      current,
      onCurrent,
      showTooltip
    } = toRefs(props)

    const container = ref()
    const indicatorContainer = ref()
    const indicator = ref()
    const visibleTip = ref(false)

    const setIndicatorX = (x: number, w: number) => {
      if (onCurrent?.value) {
        const width = toFixed((x / w) * 100, 6)
        if (width) {
          const format = width > 100 ? 100 : width < 0 ? 0 : width
          onCurrent.value(format)
        }
      }
    }

    const setAudioCurrent = (indicatorX: number, indicatorW: number) => {
      if (onChange?.value) {
        onChange.value(indicatorX, indicatorW)
      }
    }

    onMounted(() => {
      const { width } = (container.value as HTMLElement).getBoundingClientRect()

      const handleClick = (e: MouseEvent) => {
        if (!draging?.value) {
          const { x } = (container.value as HTMLElement).getBoundingClientRect()
          const { clientX } = e
          requestAnimationFrame(() => {
            setIndicatorX(clientX - x, width)
            setAudioCurrent(clientX - x, width)
          })
        }
      }

      const { start, stop } = useDrag(
        indicatorContainer.value as HTMLElement,
        indicator.value as HTMLElement,
        {
          moveCB(x) {
            requestAnimationFrame(() => {
              setIndicatorX(x, width)
            })
          },
          startCB() {
            visibleTip.value = true
            context.emit('update:draging', true)
          },
          stopCB(x) {
            visibleTip.value = false
            context.emit('update:draging', false)
            setAudioCurrent(x, width)
          },
          horizontal: true
        }
      )

      watch(
        canDrage,
        canDrage => {
          if (canDrage) {
            on(indicator.value as HTMLElement, 'click', e =>
              e.stopPropagation()
            )
            on(container.value as HTMLElement, 'click', handleClick)
            start()
          } else {
            stop()
          }
        },
        { immediate: true }
      )
    })

    const slot = context.slots as Slots

    return () => (
      <div class={prefix}>
        {slot.prefix ? slot.prefix() : ''}
        <div
          ref={container}
          class={classnames(`${prefix}-command`, {
            [`${prefix}-command-active`]: draging?.value
          })}
        >
          <BufferBlock block={block?.value}></BufferBlock>
          <div
            ref={indicatorContainer}
            class={`${prefix}-command--indicator`}
            style={{ width: current.value + '%' }}
          >
            {showTooltip.value ? (
              <Tooltip
                v-model={[visibleTip.value, 'visible']}
                trigger="focus"
                v-slots={{
                  title: () => (
                    <div class={`${prefix}-tip`}>{current.value | 0}</div>
                  ),
                  default: () => <button ref={indicator}></button>
                }}
              ></Tooltip>
            ) : (
              <button ref={indicator}></button>
            )}
          </div>
        </div>
        {slot.suffix ? slot.suffix() : ''}
      </div>
    )
  }
})