function scroll (offsetTop) {
  [document.body, document.documentElement].forEach((ele) => {
    // eslint-disable-next-line
    TweenLite.to(
      ele,
      0.4,
      {
        scrollTop: offsetTop,
        ease: Power2.easeOut // eslint-disable-line
      }
    )
  })
}

function getAttrTag (line) {
  return `[data-source-line="${line}"]`
}

function getPreLineOffsetTop (line) {
  let currentLine = line - 1
  let ele = null
  while (currentLine > 0 && !ele) {
    ele = document.querySelector(getAttrTag(currentLine))
    if (!ele) {
      currentLine -= 1
    }
  }
  return [
    currentLine >= 0 ? currentLine : 0,
    ele ? ele.offsetTop : 0
  ]
}

function getNextLineOffsetTop (line, len) {
  let currentLine = line + 1
  let ele = null
  while (currentLine < len && !ele) {
    ele = document.querySelector(getAttrTag(currentLine))
    if (!ele) {
      currentLine += 1
    }
  }
  return [
    currentLine < len ? currentLine : len - 1,
    ele ? ele.offsetTop : document.documentElement.scrollHeight
  ]
}

function topOrBottom (line, len) {
  if (line === 0) {
    scroll(0)
  } else if (line === len - 1) {
    scroll(document.documentElement.scrollHeight)
  }
}

function relativeScroll (line, ratio, len) {
  let offsetTop = 0
  const lineEle = document.querySelector(`[data-source-line="${line}"]`)
  if (lineEle) {
    offsetTop = lineEle.offsetTop
  } else {
    const pre = getPreLineOffsetTop(line)
    const next = getNextLineOffsetTop(line, len)
    offsetTop = pre[1] + ((next[1] - pre[1]) * (line - pre[0]) / (next[0] - pre[0]))
  }
  scroll(offsetTop - document.documentElement.clientHeight * ratio)
}

export default {
  relative: function ({
    cursor,
    winline,
    winheight,
    len
  }) {
    const line = cursor - 1
    const ratio = winline / winheight
    if (line === 0 || line === len - 1) {
      topOrBottom(line, len)
    } else {
      relativeScroll(line, ratio, len)
    }
  },
  middle: function ({
    cursor,
    // winline,
    // winheight,
    len
  }) {
    const line = cursor - 1
    if (line === 0 || line === len - 1) {
      topOrBottom(line, len)
    } else {
      relativeScroll(line, 0.5, len)
    }
  },
  top: function ({
    cursor,
    winline,
    // winheight,
    len
  }) {
    let line = cursor - 1
    if (line === 0 || line === len - 1) {
      topOrBottom(line, len)
    } else {
      line = cursor - winline
      relativeScroll(line, 0, len)
    }
  }
}