<template>
  <div class="indicator-home">
    <div class="notice" :style="noticeStyle"><span>下拉刷新内容</span></div>
    <div ref="toolbar" class="toolbar" :style="toolbarStyle">
      <Icon
        icon="tabler:menu-deep"
        class="search"
        style="transform: rotateY(180deg)"
        @click="$emit('showSlidebar')"
      />
      <div ref="tabCtn" class="tab-ctn">
        <div ref="tabs" class="tabs">
          <div
            v-for="(label, i) in tabLabels"
            :key="label"
            class="tab"
            :class="{ active: index === i }"
            @click.stop="change(i)"
          >
            <span>{{ label }}</span>
          </div>
        </div>
        <div ref="indicator" class="indicator" />
      </div>
      <Icon icon="ion:search" class="search" @click="_no" />
    </div>
  </div>
</template>

<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
import bus from '@/utils/bus'
import { _css } from '@/utils/dom'
import { _no } from '@/utils/index'

const props = defineProps({
  loading: { type: Boolean, default: false },
  name: { type: String, default: '' },
  index: { type: Number, default: 0 },
})

const emit = defineEmits<{ 'update:index': [number]; showSlidebar: [] }>()

const tabLabels = ['我的', '推荐']
const tabCtn = ref<HTMLElement | null>(null)
const tabs = ref<HTMLElement | null>(null)
const indicator = ref<HTMLElement | null>(null)
const lefts = ref<number[]>([])
const indicatorSpace = ref(0)
const moveY = ref(0)
const judgeValue = 20
const homeRefresh = 60

const transform = computed(
  () =>
    `translate3d(0, ${moveY.value - judgeValue > homeRefresh ? homeRefresh : moveY.value - judgeValue}px, 0)`,
)

const toolbarStyle = computed(() => {
  if (props.loading) {
    return { opacity: 1, transitionDuration: '300ms', transform: 'translate3d(0, 0, 0)' }
  }
  if (moveY.value) {
    return {
      opacity: 1 - (moveY.value - judgeValue) / (homeRefresh / 2),
      transform: transform.value,
    }
  }
  return { opacity: 1, transitionDuration: '300ms', transform: 'translate3d(0, 0, 0)' }
})

const noticeStyle = computed(() => {
  if (props.loading) return { opacity: 0 }
  if (moveY.value) {
    return {
      opacity: (moveY.value - judgeValue) / (homeRefresh / 2) - 0.5,
      transform: transform.value,
    }
  }
  return { opacity: 0 }
})

function updateIndicatorLeft(index: number, animate = true) {
  if (!indicator.value || !lefts.value.length) return
  const safeIndex = Math.max(0, Math.min(index, lefts.value.length - 1))
  _css(indicator.value, 'transition-duration', animate ? '300ms' : '0ms')
  _css(indicator.value, 'left', lefts.value[safeIndex] + 'px')
}

function change(index: number) {
  emit('update:index', index)
  updateIndicatorLeft(index)
}

function initTabs() {
  if (!tabs.value || !indicator.value || !tabCtn.value) return
  const indicatorWidth = _css(indicator.value, 'width') as number
  const tabCtnLeft = tabCtn.value.getBoundingClientRect().left
  const positions: number[] = []
  for (let i = 0; i < tabs.value.children.length; i++) {
    const item = tabs.value.children[i] as HTMLElement
    const rect = item.getBoundingClientRect()
    positions.push(rect.left - tabCtnLeft + (rect.width * 0.5 - indicatorWidth / 2))
  }
  lefts.value = positions
  indicatorSpace.value = positions.length > 1 ? positions[1] - positions[0] : 0
  updateIndicatorLeft(props.index, false)
}

function move(val?: unknown) {
  const e = val as number
  if (!indicator.value || !indicatorSpace.value) return
  const safeIndex = Math.max(0, Math.min(props.index, lefts.value.length - 1))
  _css(indicator.value, 'transition-duration', '0ms')
  _css(
    indicator.value,
    'left',
    lefts.value[safeIndex] - e / (window.innerWidth / indicatorSpace.value) + 'px',
  )
}

function end(val?: unknown) {
  const index = val as number
  moveY.value = 0
  updateIndicatorLeft(index)
  setTimeout(() => {
    if (indicator.value) _css(indicator.value, 'transition-duration', '0ms')
  }, 300)
}

watch(
  () => props.index,
  (index) => {
    nextTick(() => updateIndicatorLeft(index))
  },
)

onMounted(() => {
  nextTick(() => {
    initTabs()
    requestAnimationFrame(initTabs)
  })
  bus.on(props.name + '-moveX', move)
  bus.on(props.name + '-moveY', (e) => {
    moveY.value = e as number
  })
  bus.on(props.name + '-end', end)
})

onUnmounted(() => {
  bus.off(props.name + '-moveX', move)
  bus.off(props.name + '-moveY')
  bus.off(props.name + '-end', end)
})
</script>

<style scoped lang="less">
.indicator-home {
  position: absolute;
  font-size: 16rem;
  top: 0;
  left: 0;
  z-index: 2;
  width: 100%;
  color: white;
  height: var(--home-header-height);
  font-weight: bold;

  .notice {
    opacity: 0;
    top: 0;
    position: absolute;
    width: 100vw;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  .toolbar {
    z-index: 2;
    position: relative;
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    padding: 0 15rem;
    display: flex;
    justify-content: center;
    align-items: center;

    .tab-ctn {
      position: relative;
      display: flex;
      justify-content: center;

      .tabs {
        display: flex;
        justify-content: center;
        align-items: center;
        gap: 40rem;

        .tab {
          transition: color 0.3s;
          color: rgba(255, 255, 255, 0.7);
          font-size: 17rem;
          cursor: pointer;
          white-space: nowrap;

          &.active {
            color: white;
          }
        }
      }

      .indicator {
        position: absolute;
        bottom: -6rem;
        height: 2.6rem;
        width: 26rem;
        background: #fff;
        border-radius: 5rem;
      }
    }

    .search {
      position: absolute;
      top: 0;
      bottom: 0;
      margin: auto 0;
      height: 24rem;
      display: flex;
      align-items: center;
      color: white;
      font-size: 24rem;
      cursor: pointer;

      &:first-of-type {
        left: 15rem;
      }

      &:last-of-type {
        right: 15rem;
      }
    }
  }
}
</style>
