import {
  callPageHook
} from '../util'

function addKeepAliveInclude (componentName) {
  if (this.keepAliveInclude.indexOf(componentName) === -1) { // 目标页面,自动 include
    this.keepAliveInclude.push(componentName)
  }
}

let deltaIds = []

function removeKeepAliveInclude (componentNameOrDelta) {
  if (typeof componentNameOrDelta === 'number') {
    deltaIds = this.keepAliveInclude.splice(-(componentNameOrDelta - 1)).map(name => {
      return parseInt(name.split('-').pop())
    })
  } else {
    const index = this.keepAliveInclude.indexOf(componentNameOrDelta)
    if (index !== -1) {
      this.keepAliveInclude.splice(index, 1)
    }
  }
}

let positionStore = Object.create(null)

export function getTabBarScrollPosition (id) {
  return positionStore[id]
}

function saveTabBarScrollPosition (id) {
  positionStore[id] = {
    x: window.pageXOffset,
    y: window.pageYOffset
  }
}

function switchTab (routes, to, from) {
  if (
    to &&
    from &&
    to.meta.isTabBar &&
    from.meta.isTabBar
  ) { // tabbar 跳 tabbar
    saveTabBarScrollPosition(from.params.__id__)
  }
  // 关闭非 tabBar 页面
  const pages = getCurrentPages()
  for (let i = pages.length - 1; i >= 0; i--) {
    const pageVm = pages[i]
    const meta = pageVm.$page.meta
    if (!meta.isTabBar) {
      removeKeepAliveInclude.call(this, meta.name + '-' + pageVm.$page.id)
      callPageHook(pageVm, 'onUnload')
    }
  }
}

function reLaunch (toName) {
  __uniConfig.reLaunch = (__uniConfig.reLaunch || 1) + 1
  // 关闭所有页面
  const pages = getCurrentPages(true)
  for (let i = pages.length - 1; i >= 0; i--) {
    callPageHook(pages[i], 'onUnload')
    // 重新reLaunch至首页可能会被keepAlive，先手动强制destroy
    pages[i].$destroy()
  }
  this.keepAliveInclude = []
  // 清空 positionStore
  positionStore = Object.create(null)
}

let currentPages = []

function beforeEach (to, from, next, routes) {
  currentPages = getCurrentPages(true) // 每次 beforeEach 时获取当前currentPages，因为 afterEach 之后，获取不到上一个 page 了，导致无法调用 onUnload
  const fromId = from.params.__id__
  const toId = to.params.__id__
  const toName = to.meta.name + '-' + toId
  if (toId === fromId && to.type !== 'reLaunch') { // 相同页面阻止
    // 处理外部修改 history 导致卡在当前页面的问题
    if (to.fullPath !== from.fullPath) {
      addKeepAliveInclude.call(this, toName)
      next()
    } else {
      next(false)
    }
  } else if (to.meta.id && to.meta.id !== toId) { // id 不妥，replace跳转
    next({
      path: to.path,
      replace: true
    })
  } else {
    const fromName = from.meta.name + '-' + fromId

    switch (to.type) {
      case 'navigateTo':
        break
      case 'redirectTo':
        // 关闭前一个页面
        removeKeepAliveInclude.call(this, fromName)
        if (from.meta) {
          if (from.meta.isQuit) { // 如果 redirectTo 的前一个页面是 quit 类型，则新打开的页面也是 quit
            to.meta.isQuit = true
            to.meta.isEntry = !!from.meta.isEntry
          }
          // 小程序没有这个逻辑，当时为何加了保留并更新 tabBar 的逻辑？
          // if (from.meta.isTabBar) { // 如果是 tabBar，需要更新系统组件 tabBar 内的 list 数据
          //   to.meta.isTabBar = true
          //   to.meta.tabBarIndex = from.meta.tabBarIndex
          //   const appVm = getApp().$children[0]
          //   appVm.$set(appVm.tabBar.list[to.meta.tabBarIndex], 'pagePath', to.meta.pagePath)
          // }
        }

        break
      case 'switchTab':
        switchTab.call(this, routes, to, from)
        break
      case 'reLaunch':
        reLaunch.call(this, toName)
        to.meta.isQuit = true // reLaunch后，该页面为 quit 类型
        break
      default:
        // 后退或非 API 访问
        if (fromId && fromId > toId) { // back
          removeKeepAliveInclude.call(this, fromName)
          if (this.$router._$delta > 1) {
            removeKeepAliveInclude.call(this, this.$router._$delta)
          }
        }
        break
    }

    if (to.type !== 'reLaunch' && to.type !== 'redirectTo' && from.meta.id) { // 如果不是 reLaunch、redirectTo，且 meta 指定了 id
      addKeepAliveInclude.call(this, fromName)
    }
    // if (to.type !== 'reLaunch') { // TODO 如果 reLaunch，1.keepAlive的话，无法触发页面生命周期，并刷新页面，2.不 keepAlive 的话，页面状态无法再次保留,且 routeView 的 cache 有问题
    addKeepAliveInclude.call(this, toName)
    // }
    if (process.env.NODE_ENV !== 'production') {
      console.debug(`Core：keepAliveInclude=${JSON.stringify(this.keepAliveInclude)}`)
    }
    /* eslint-disable no-undef */
    if (__PLATFORM__ === 'h5') {
      if (to.meta && to.meta.name) {
        document.body.className = 'uni-body ' + to.meta.name
        const nvueDirKey = 'nvue-dir-' + __uniConfig.nvue['flex-direction']
        if (to.meta.isNVue) {
          document.body.setAttribute('nvue', '')
          document.body.setAttribute(nvueDirKey, '')
        } else {
          document.body.removeAttribute('nvue')
          document.body.removeAttribute(nvueDirKey)
        }
      }
    }

    next()
  }
}

function afterEach (to, from) {
  const fromId = from.params.__id__
  const toId = to.params.__id__
  let fromVm
  // 使用 beforeEach 时的 pages
  if (from.meta.isSet) {
    fromVm = currentPages.find(pageVm => pageVm.$page.meta.pagePath === from.meta.pagePath)
  } else {
    fromVm = currentPages.find(pageVm => pageVm.$page.id === fromId)
  }

  function unloadPage (vm) {
    if (vm) {
      callPageHook(vm, 'onUnload')
      const index = currentPages.indexOf(vm)
      if (index >= 0) {
        currentPages.splice(index, 1)
      }
    }
  }

  switch (to.type) {
    case 'navigateTo': // 前一个页面触发 onHide
      fromVm && callPageHook(fromVm, 'onHide')
      break
    case 'redirectTo': // 前一个页面触发 onUnload
      unloadPage(fromVm)
      break
    case 'switchTab':
      if (from.meta.isTabBar) { // 前一个页面是 tabBar 触发 onHide，非 tabBar 页面在 beforeEach 中已触发 onUnload
        fromVm && callPageHook(fromVm, 'onHide')
      }
      break
    case 'reLaunch':
      break
    default:
      if (fromId && fromId > toId) { // history back
        unloadPage(fromVm)
        if (this.$router._$delta > 1) {
          deltaIds.reverse().forEach(deltaId => {
            const pageVm = currentPages.find(pageVm => pageVm.$page.id === deltaId)
            unloadPage(pageVm)
          })
        }
      }
      break
  }

  delete this.$router._$delta
  deltaIds.length = 0

  if (to.type !== 'reLaunch') { // 因为 reLaunch 会重置 id，故不触发 onShow,switchTab 在 beforeRouteEnter 中触发
    // 直接获取所有 pages,getCurrentPages 正常情况下仅返回页面栈内，传 true 则返回所有已存在（主要是 tabBar 页面）
    const pages = getCurrentPages(true)
    let toVm
    // 使用最新的 pages
    if (to.meta.isSet) {
      toVm = pages.find(pageVm => pageVm.$page.meta.pagePath === to.meta.pagePath)
    } else {
      toVm = pages.find(pageVm => pageVm.$page.id === toId)
    }
    if (toVm) { // 目标页面若已存在，则触发 onShow
      // 延迟执行 onShow，防止与 UniServiceJSBridge.emit('onHidePopup') 冲突。
      setTimeout(function () {
        if (__PLATFORM__ === 'h5') {
          UniServiceJSBridge.emit('onNavigationBarChange', toVm.$parent.$parent.navigationBar)
        }
        callPageHook(toVm, 'onShow')
      }, 0)
      if (__PLATFORM__ === 'h5') {
        document.title = toVm.$parent.$parent.navigationBar.titleText
      }
    }
  }
}
export default function initRouterGuard (appVm, routes) {
  // 处理keepAliveInclude
  appVm.$router.beforeEach(function (to, from, next) {
    beforeEach.call(appVm, to, from, next, routes)
  })
  // 处理前进时的 onUnload,onHide 和后退时的 onShow
  appVm.$router.afterEach(function (to, from) {
    afterEach.call(appVm, to, from)
  })
}
