import getRedirectRouter from './config/redirectRouter';
import VueRouter from 'vue-router'

const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location, resolve, reject) {
  if (resolve || reject) return originalPush.call(this, location, resolve, reject)
  return originalPush.call(this, location).catch(err => err)
}

function handleRedirectForCleanUrls(router, to) {
  if (isRouteExists(router, to.path)) {
    return to.path
  } else {
    if (!/(\/|\.html)$/.test(to.path)) {
      const endingSlashUrl = to.path + '/'
      const endingHtmlUrl = to.path + '.html'
      if (isRouteExists(router, endingHtmlUrl)) {
        return endingHtmlUrl
      } else if (isRouteExists(router, endingSlashUrl)) {
        return endingSlashUrl
      } else {
        return to.path.replace(/\.md$/, '')
      }
    } else if (/\/$/.test(to.path)) {
      const endingHtmlUrl = to.path.replace(/\/$/, '') + '.html'
      if (isRouteExists(router, endingHtmlUrl)) {
        return endingHtmlUrl
      } else {
        return to.path
      }
    } else {
      return to.path
    }
  }
}

function isRouteExists(router, path) {
  const pathLower = path.toLowerCase()
  return router.options.routes.some(route => route.path.toLowerCase() === pathLower)
}

function handlePath(router, to) {
  // 重定向路由表
  const redirectRouter = getRedirectRouter(to)
  if (redirectRouter) return redirectRouter

  const id = to.query.id
  const hash = decodeURIComponent(id || to.hash).toLowerCase()
  const redirectPath = handleRedirectForCleanUrls(router, to)
  if (id) {
    return {
      path: redirectPath,
      replace: true,
      hash
    }
  }
  if (redirectPath !== to.path) {
    return {
      path: redirectPath,
      replace: true,
      hash
    }
  }
  if (/\bREADME\b/.test(to.path)) {
    return {
      path: to.path.replace(/\bREADME\b/, ''),
      replace: true,
      hash
    }
  }
}

export default ({
  Vue,
  options,
  router,
  siteData
}) => {
  let mounted = false
  const ScrollBehavior = 'instant'

  router.beforeHooks.unshift((to, from, next) => {
    next(handlePath(router, to))
  })

  router.options.scrollBehavior = function scrollBehavior(to, from, savedPosition) {
    if (savedPosition) {
      return window.scrollTo({
        top: savedPosition.y,
        behavior: ScrollBehavior,
      });
    }
    else if (to.hash) {
      if (Vue.$vuepress.$get('disableScrollBehavior')) {
        return false;
      }
      const selector = decodeURIComponent(to.hash.toLowerCase())
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (!mounted) mounted = true
          const targetElement = document.querySelector(selector);
          if (targetElement) {
            return window.scrollTo({
              top: getElementPosition(targetElement).y,
              behavior: ScrollBehavior,
            });
          }
          return resolve(false);
        }, mounted ? 0 : 700)
      })
    }
    else {
      return window.scrollTo({
        top: 0,
        behavior: ScrollBehavior,
      });
    }
  }
}

function getElementPosition(el) {
  const docEl = document.documentElement;
  const docRect = docEl.getBoundingClientRect();
  const elRect = el.getBoundingClientRect();
  return {
    x: elRect.left - docRect.left,
    y: elRect.top - docRect.top,
  };
}