import { onUnmounted, reactive, onMounted } from 'vue'
import { UseAudioFastCall, UseAudioManager, UseScheduler, UseSchedulerFastCall, UseSchedulerOnceProps } from './types'
import dayjs from 'dayjs'

/**
 *
 * @description 重复执行的定时器， 会在组件的unMounted阶段销毁
 *
 */
export const useScheduler: UseScheduler = ({
  delay,
  cb
}) => {
  const stx: UseSchedulerFastCall = {
    timeId: null,
    start: () => {},
    pause: () => {},
    stop: () => {},
    onPlaying: () => {}
  }

  let timeId: NodeJS.Timer | null = null

  const playing = () => {}

  const clearScheduler = () => clearInterval(timeId as NodeJS.Timer)

  onUnmounted(clearScheduler)

  stx.start = () => {
    timeId = setInterval(() => {
      cb()
      playing()
    }, delay)
  }

  stx.pause = () => clearScheduler()

  stx.onPlaying = playing

  return [stx]
}

/**
 * @description 执行一定的定时器， 会在执行完后销毁
 */

export const useSchedulerOnce = ({
  cb,
  delay
}: UseSchedulerOnceProps): void => {
  const timeId = setTimeout(() => {
    clearTimeout(timeId)
    cb()
  }, delay)
}

/**
 * @description 音频 全局共享一个音频 单例
 * @description 音频的duration 需要在oncanplay事件中才能获取到
 * @return [UseAudioFastCall, HTMLAudioElemen]
 */

export const useAudioManager: UseAudioManager = ({
  url = '',
  format = ''
}) => {
  const fco = reactive<UseAudioFastCall>({
    src: '',
    playing: false,
    updateTime: '',
    duration: '',
    percentage: 0,
    play: () => {},
    pause: () => {},
    onended: () => {}
  })
  if (typeof window.$audio === 'object') {
    window.$audio.src = url
    fco.play = window.$audio.play.bind(window.$audio)
    fco.pause = window.$audio.pause
    return [fco, window.$audio]
  } else {
    console.log('initAudio');
    
    const atx = new Audio(url)

    atx.onplaying = () => {
      fco.playing = true
    }

    atx.oncanplay = () => {
      fco.duration = dayjs(Math.round(atx.duration) * 1000).format(format)
    }

    atx.ontimeupdate = () => {
      const updateTime = Math.round(atx.currentTime) * 1000
      fco.updateTime = format ? dayjs(updateTime).format(format) : String(updateTime)
      fco.percentage = atx.currentTime / atx.duration
    }

    fco.play = atx.play.bind(atx)

    fco.pause = atx.pause.bind(atx)

    fco.onended = atx.onended

    atx.onended = () => {
      fco.playing = false
    }

    atx.pause = () => {
      fco.playing = false
    }

    Object.defineProperty(fco, 'src', {
      get() {
        return atx.src
      },
      set (v) {
        atx.src = v
        return v
      }
    })

    window.$audio = atx

    onUnmounted(() => {
      fco.pause && fco.pause()
    })

    return [fco, window.$audio]
  }
}

/**
 * 它返回一个以回调函数为参数的函数，回调函数将在设备方向改变时被调用。
 * @returns 具有函数的数组。
 */
export const useDeviceDire = (): [(cb: (dire: 'H' | 'V') => void) => void ] => {
  let dire: 'H' | 'V' = 'H'

  let _cb = (dire: 'H' | 'V') => {}

  const direChange = (cb: (dire: 'H' | 'V') => void) => {
    _cb = cb
  }

  const getDire = () => {
    if (window.orientation === 180 || window.orientation === 0) {
      dire = 'V'
      _cb(dire)
    }
    if (window.orientation === 90 || window.orientation === -90) {
      dire = 'H'
      _cb(dire)
    }
  }

  window.addEventListener('orientationchange', getDire)

  onMounted(getDire)

  onUnmounted(() => {
    window.removeEventListener('orientationchange', () => {})
  })

  return [direChange]
}



export const useDrag = (
  el: HTMLElement,
  options: {
    onDragStart?: (ev: TouchEvent) => void,
    onDraging?: (ev: TouchEvent) => void,
    onDragEnd?: (ev: TouchEvent, setPos: any) => void,
  }
) => {
  console.dir(el);
  
  const { onDragStart, onDraging, onDragEnd } = options
  let startPos = { x: 0, y: 0 }

  const getOffsetTopScreen = (ele: HTMLElement) => {

    let _ele = ele
    let T = _ele.offsetTop
    while (_ele.offsetParent !== null) {
      _ele = _ele.offsetParent  as HTMLElement
      T += ele.offsetTop
      return T
    }
  }

  const getOffsetLeftScreen = (ele: HTMLElement) => {

    let _ele = ele
    let T = _ele.offsetLeft
    while (_ele.offsetParent !== null) {
      _ele = _ele.offsetParent  as HTMLElement
      T += ele.offsetLeft
      return T
    }
  }

  const offsetTopScreen = getOffsetTopScreen(el)!
  const offsetLeftScreen = getOffsetLeftScreen(el)!

  const touchmove = (ev: TouchEvent) => {
    const target = (<HTMLElement>ev.target)

    if (target.id == el.id) return

    let x = 0, y = 0

    
    const { clientX, clientY } = ev.touches[0]
    if (clientY - startPos.y < 0) {
      y = 0
    } else if (clientY - startPos.y > 426) {
      y = 426
    } else {
      y = clientY - startPos.y 
    }
    
    if (clientX - startPos.x < 0) {
      x = 0
    } else if (clientX - startPos.x >  el.offsetWidth - 46) {
      
      x =  el.offsetWidth - 46 

    } else {
      x = clientX - startPos.x 
    }

    if ( (clientX > el.offsetLeft && clientX <el.offsetWidth) && clientY < offsetTopScreen + 46)  {
      target.style.transform = `translate(${x}px, ${y}px)`
    } else if ( (clientX > el.offsetLeft && clientX < el.offsetWidth) && clientY > offsetTopScreen + el.offsetHeight - 46 ) {
      target.style.transform = `translate(${x}px, ${y}px)`
    } else if ( clientX < offsetLeftScreen && clientY > offsetTopScreen &&  clientY < offsetTopScreen + el.offsetHeight) {
      target.style.transform = `translate(${x}px, ${y}px)`
    } else if (clientX > el.offsetWidth - 46 && clientY > offsetTopScreen &&  clientY < offsetTopScreen + el.offsetHeight) {
      target.style.transform = `translate(${x}px, ${y}px)`
    }
    
    else if (
      clientX > offsetLeftScreen &&
      clientX < offsetLeftScreen + el.offsetWidth  &&
      clientY > offsetTopScreen  &&
      clientY < offsetTopScreen + el.offsetHeight
    ){

      target.style.transform = `translate(${ x}px, ${ y}px)`
      onDraging && onDraging(ev)
    }
  }

  const touchstart = (ev: TouchEvent) => {
    console.log(ev);

    const target = (<HTMLElement>ev.target)

    if (target.id == el.id) return
    const deviationX = Number(target.style.width.replace(/px/, '')) / 2
    const deviationY = Number(target.style.height.replace(/px/, '')) / 2
    startPos = { x: (<any>target).x + deviationX, y: (<any>target).y + deviationY }
    onDragStart && onDragStart!(ev)
  }

  const touchend = (ev: TouchEvent) => {
    const target = (<HTMLElement>ev.target)
    if (target.id == el.id) return
    onDragEnd && onDragEnd!(ev, setPos)
  }
  
  function setPos (
    el: HTMLElement,
    { x, y }: {x: number, y: number},
    druation: number
  ) {
    el.style.transition = `transform ${druation}s`
    el.style.transform = `translate(${x}px, ${y}px)`
    const timeId = setTimeout(() => {
      el.style.transition = 'none'
      clearTimeout(timeId)
    }, druation * 1000)
  }

  el.addEventListener('touchstart', touchstart)

  el.addEventListener('touchmove', touchmove)

  el.addEventListener('touchend', touchend)

  onUnmounted(() => {
    el.removeEventListener('touchmove', touchmove)
    el.removeEventListener('touchstart', touchstart)
    el.removeEventListener('touchend', touchend)
  })

  return []
}


/**
 * useLocalStorage 函数允许在 TypeScript 的本地存储中存储和检索数据。
 * @param {string} key - 一个字符串，表示将在其下将值存储在本地存储中的键。
 * @param {any} defalutValue - 默认值是初始值，如果给定键没有现有值，则将存储在本地存储中。
 * @returns 具有两个元素的数组：存储在本地存储中的给定键的当前值，以及可用于更新存储在本地存储中的给定键值的函数。
 */
export const useLocalStorage = (key: string): [any, (value: any) => void] => {

  let value = null
  
  const fn = (value: any) => {
    if (typeof value == 'object') {
      window.localStorage.setItem(key, JSON.stringify(value))
    } else if (typeof value == 'string') {
      console.log('set:', value);
      
      window.localStorage.setItem(key, value)
    }  
  }

  const _get = () => {
    const r = window.localStorage.getItem(key)
    console.log("_getToken:", r);
    
    try {
      value = JSON.parse(r!)
    } catch (error) {
      value = r
    }
    return value
  }
  
  return [ _get(), fn]

}
