import {
  supportsPassive
} from 'uni-shared'

import {
  getTargetDataset
} from 'uni-helpers/index'

import {
  wrapperMPEvent
} from 'uni-helpers/patch'

import getWindowOffset from 'uni-platform/helpers/get-window-offset'

function processTarget (target, detail, checkShadowRoot = false) {
  const res = {
    id: target.id,
    offsetLeft: target.offsetLeft,
    offsetTop: target.offsetTop,
    dataset: getTargetDataset(target)
  }
  if (detail) {
    Object.assign(res, detail)
  }
  return res
}

function processTouches (touches) {
  if (touches) {
    const res = []

    const {
      top
    } = getWindowOffset()

    for (let i = 0; i < touches.length; i++) {
      const touch = touches[i]
      res.push({
        identifier: touch.identifier,
        pageX: touch.pageX,
        pageY: touch.pageY - top,
        clientX: touch.clientX,
        clientY: touch.clientY - top,
        force: touch.force || 0
      })
    }
    return res
  }
  return []
}

function isMouseEvent (name) {
  return name.startsWith('mouse') || ['contextmenu'].includes(name)
}

export function processEvent (name, $event = {}, detail = {}, target = {}, currentTarget = {}) {
  if ($event._processed) {
    $event.type = detail.type || name
    return $event
  }

  // fixed 针对小程序 click（tap）事件，补充事件详情
  if (name === 'click') {
    const {
      top
    } = getWindowOffset()

    detail = {
      x: $event.x,
      y: $event.y - top
    }
    $event.touches = $event.changedTouches = [{
      force: 1,
      identifier: 0,
      clientX: $event.clientX,
      clientY: $event.clientY,
      pageX: $event.pageX,
      pageY: $event.pageY
    }]
  }

  // fixed mp-vue
  const ret = wrapperMPEvent({
    type: detail.type || name,
    timeStamp: $event.timeStamp || 0,
    detail: detail,
    target: processTarget(target, detail),
    currentTarget: processTarget(currentTarget, false, true),
    // 只处理系统事件
    touches: ($event instanceof Event || $event instanceof CustomEvent) ? processTouches($event.touches) : $event.touches,
    changedTouches: ($event instanceof Event || $event instanceof CustomEvent) ? processTouches($event.changedTouches)
      : $event.changedTouches,
    preventDefault () {},
    stopPropagation () {}
  })

  if (isMouseEvent(name)) {
    const {
      top
    } = getWindowOffset()
    ret.pageX = $event.pageX
    ret.pageY = $event.pageY - top
    ret.clientX = $event.clientX
    ret.clientY = $event.clientY - top
  }

  if (__PLATFORM__ === 'app-plus') {
    const nid = currentTarget.getAttribute('_i')
    ret.options = {
      nid
    }
    // 保留原始 currentTarget 方便后续对比
    ret.$origCurrentTarget = currentTarget
  }

  return ret
}

const LONGPRESS_TIMEOUT = 350
const LONGPRESS_THRESHOLD = 10

const passiveOptions = supportsPassive ? {
  passive: true
} : false

let longPressTimer = false

function clearLongPressTimer () {
  if (longPressTimer) {
    clearTimeout(longPressTimer)
    longPressTimer = false
  }
}

let startPageX = 0
let startPageY = 0

function touchstart (evt) {
  clearLongPressTimer()
  if (evt.touches.length !== 1) {
    return
  }
  const {
    pageX,
    pageY
  } = evt.touches[0]

  startPageX = pageX
  startPageY = pageY

  longPressTimer = setTimeout(function () {
    const customEvent = new CustomEvent('longpress', {
      bubbles: true,
      cancelable: true,
      target: evt.target,
      currentTarget: evt.currentTarget
    })
    customEvent.touches = evt.touches
    customEvent.changedTouches = evt.changedTouches
    evt.target.dispatchEvent(customEvent)
  }, LONGPRESS_TIMEOUT)
}

function touchmove (evt) {
  if (!longPressTimer) {
    return
  }

  if (evt.touches.length !== 1) {
    return clearLongPressTimer()
  }

  const {
    pageX,
    pageY
  } = evt.touches[0]

  if (Math.abs(pageX - startPageX) > LONGPRESS_THRESHOLD || Math.abs(pageY - startPageY) > LONGPRESS_THRESHOLD) {
    return clearLongPressTimer()
  }
}

export function initEvents () {
  window.addEventListener('touchstart', touchstart, passiveOptions)
  window.addEventListener('touchmove', touchmove, passiveOptions)
  window.addEventListener('touchend', clearLongPressTimer, passiveOptions)
  window.addEventListener('touchcancel', clearLongPressTimer, passiveOptions)
}
