<template>
  <scroll-view 
    :scroll-x="true"
    :scroll-with-animation="true"
    :show-scrollbar="false"
    :scroll-left="currentScrollPos"
    :style="{
      width: theme.resolveSize(props.width),
      height: theme.resolveSize(props.height),
      ...innerStyle,
    }"
  >
    <view 
      class="nana-tabs"
      :style="{
        minWidth: theme.resolveSize(props.width),
        height: theme.resolveSize(props.height),
      }"
    >
      <Touchable
        v-for="(tab, index) in filteredTabs"
        :ref="(ref) => tabsRefs[index] = ref"
        :key="index"
        direction="row"
        :pressedColor="themedUnderlayColor"
        :innerStyle="itemStyle"
        :width="itemWidthArr[index].width > 0 ?
            theme.resolveSize(itemWidthArr[index].width - tabPaddingHorizontal * 2) :
            undefined"
        :touchable="!tab.disabled"
        :flexShrink="0"
        :padding="[ 0, tabPaddingHorizontal ]"
        center
        innerClass="tab-item"
        @click="onTabClick(index)"
      >
        <slot name="tab" 
          :tab="tab"
          :index="index" 
          :width="itemWidthArr[index].width" 
          :active="currentIndex == index"
        >
          <Badge
            content="0"
            v-bind="tab.badgeProps"
          >
            <text
              class="tab-item-text"
              :style="{
                color: tab.disabled ? themedDisableTextColor : (currentIndex == index ? themedActiveTextColor : themedTextColor),
                whiteSpace: props.noWrap ? 'nowrap' : 'normal',
                ...(currentIndex == index ? activeTextStyle : textStyle),
              }"
            >
              {{ tab.text }}
            </text>
          </Badge>
        </slot>
      </Touchable>

      <view 
		    v-if="showIndicator"
        :style="{
          backgroundColor: theme.resolveThemeColor(activeTextColor),
          ...indicatorStyle,       
          width: `${currentIndicatorWidth}px`,
          transform: `translateX(${currentIndicatorPos}px)`,
        }"      
        :class="[
          'tab-indicator',
          indicatorAnim ? 'anim' : '',
        ]" 
      />
    </view>
  </scroll-view>
</template>

<script setup lang="ts">
import { computed, nextTick, onMounted, ref, watch } from 'vue';
import { propGetThemeVar, useTheme, type TextStyle, type ViewStyle } from '../theme/ThemeDefine';
import type { BadgeProps } from '../display/Badge.vue';
import Badge from '../display/Badge.vue';
import Touchable from '../feedback/Touchable.vue';

export interface TabsItemData {
  /**
   * 标签显示文字
   */
  text: string,
  /**
   * 自定义数据
   */
  data?: any,
  /**
   * 是否显示。
   * @default true
   */
  visible?: boolean;
  /**
   * 是否禁用选择。
   * @default false
   */
  disabled?: boolean,
  /**
   * 红点标记的自定义属性。同 Badge 组件。
   */
  badgeProps?: BadgeProps,
  /**
   * 标签宽度。此设置优先级最高, 会覆盖 Tabs 组件的设置。
   * 如果设置为-1，则根据文字宽度自动调整。
   * 如果设置为 undefined ，则使用 defaultItemWidth 。
   * @default undefined
   */
  width?: number,
  /**
   * 指示器宽度，默认值从 Tabs 组件继承。
   */
  indicatorWidth?: number,
  /**
   * 懒加载？，仅在TabsPage组件中有效
   */
  lazy?: boolean,
}
export interface TabsProps {
  /**
   * 标签数据
   */
  tabs: TabsItemData[];
  /**
   * 当前选中的标签位置
   */
  currentIndex: number;
  /**
   * 整个组件的高度
   * @default 90rpx
   */
  height?: number,
  /**
   * 整个组件的宽度
   * @default deviceWidth
   */
  width?: number,
  /**
   * 是否自动根据容器宽度调整标签宽度
   * @default true
   */
  autoItemWidth?: boolean,
  /**
   * 指示器切换标签时是否有动画效果
   * @default true
   */
  indicatorAnim?: boolean,
  /**
   * 是否在用户切换标签后自动滚动至当前选中的条目
   * @default true
   */
  autoScroll?: boolean,
  /**
   * 是否禁止标签文字换行
   * @default true
   */
  noWrap?: boolean,
  /**
   * 标签宽度，在 autoItemWidth 为 false 时有效。
   * 如果设置为-1，则根据文字宽度自动调整。
   * @default 100 （rpx)
   */
  defaultItemWidth?: number,
  /**
   * 默认的指示器宽度。
   * @default itemWidth / 4
   */
  defaultIndicatorWidth?: number,
  /**
   * 标签自定义样式
   */
  itemStyle?: ViewStyle,
  /**
   * 标签正常状态的文字颜色
   * @default text
   */
  textColor?: string,
  /**
   * 标签禁用状态的文字颜色
   * @default grey
   */
  disableTextColor?: string,
  /**
   * 标签正常状态的文字样式
   */
  textStyle?: TextStyle,
  /**
   * 标签激活状态的文字颜色
   * @default primary
   */
  activeTextColor?: string,
  /**
   * 标签激活状态的文字样式
   */
  activeTextStyle?: TextStyle,
  /**
   * 标签按下颜色
   * @default pressed.white
   */
  underlayColor?: string,
  /**
   * 指示器自定义样式
   */
  indicatorStyle?: ViewStyle,
  /**
   * 显示指示器
   * @default true
   */
  showIndicator?: boolean,

  innerStyle?: ViewStyle,
}

const emit = defineEmits([ 'update:currentIndex', 'click' ])
const props = withDefaults(defineProps<TabsProps>(), {
  height: () => propGetThemeVar('TabsDefaultHeight', 90),
  width: () => propGetThemeVar('TabsDefaultWidth', 750),
  autoItemWidth: true,
  indicatorAnim: true,
  showIndicator: true,
  autoScroll: true,
  noWrap: true,
  defaultItemWidth: () => propGetThemeVar('TabsDefaultItemWidth', 120),
  defaultIndicatorWidth: () => propGetThemeVar('TabsDefaultIndicatorWidth', 100),
  textColor: () => propGetThemeVar('TabsTextColor', 'text.title'),
  disableTextColor: () => propGetThemeVar('TabsDisableTextColor', 'grey'),
  activeTextColor: () => propGetThemeVar('TabsActiveTextColor', 'primary'),
  underlayColor: () => propGetThemeVar('TabsUnderlayColor', 'pressed.white'),
});

const theme = useTheme();

const tabPaddingHorizontal = computed(() => theme.getVar('TabsItemPaddingHorizontal', 0));
const themedUnderlayColor = computed(() => theme.resolveThemeColor(props.underlayColor));
const themedActiveTextColor = computed(() => theme.resolveThemeColor(props.activeTextColor));
const themedTextColor = computed(() => theme.resolveThemeColor(props.textColor));
const themedDisableTextColor = computed(() => theme.resolveThemeColor(props.disableTextColor));
 
const mersuredTabs = ref<(number|undefined)[]>([]);
const tabsRefs = ref<any[]>([]);
const filteredTabs = computed(() => props.tabs.filter(tab => tab.visible !== false));
const itemWidthArr = computed(() => {
  const result : {
    width: number,
    indicatorWidth: number,
  }[] = [];
  for (let i = 0; i <= filteredTabs.value.length; i++) {
    if (i === filteredTabs.value.length) {
      result.push({
        width: 0,
        indicatorWidth: 0,
      });
      nextTick(() => measureTab(i))
    } else {
      const itemWidth = filteredTabs.value[i].width || 
        (
          props.autoItemWidth ? 
            (props.width / filteredTabs.value.length) : 
            props.defaultItemWidth
      );
      const itemIndicatorWidth = filteredTabs.value[i].indicatorWidth || props.defaultIndicatorWidth || itemWidth / 4;
      result.push({
        width: itemWidth,
        indicatorWidth: itemIndicatorWidth,
      });
      if (itemWidth <= 0)
        nextTick(() => measureTab(i))
    }
  }
  return result;
});

const currentCanMeasure = ref(true);
const currentScrollPos = ref(0);
const currentIndicatorPos = ref(0);
const currentIndicatorWidth = ref(0);

function measureTab(index: number) {
  if (!currentCanMeasure.value)
    return;
  tabsRefs.value[index]?.measure().then((res: any) => {
    if (res[0])
      mersuredTabs.value[index] = res[0].width;
    else
      mersuredTabs.value[index] = uni.upx2px(props.defaultItemWidth);
  })
}
function loadPos() {
  const currentIndex = props.currentIndex;
  const current = itemWidthArr.value[currentIndex];
  if (!current)
    return;
  const itemWidth = current.width >= 0 ? uni.upx2px(current.width) : mersuredTabs.value[currentIndex] || 0;

  const targetWidth = uni.upx2px(current.indicatorWidth);
  let scrollLeft = 0;
  let targetLeft = 0;

  for (let i = currentIndex - 1; i >= 0; i--) {
    const width = itemWidthArr.value[i].width > 0 ? uni.upx2px(itemWidthArr.value[i].width) : mersuredTabs.value[i] || 0;
    targetLeft += width;
    scrollLeft += width;
  }


  if (targetWidth < itemWidth)
    targetLeft += itemWidth / 2 - targetWidth / 2;

  currentIndicatorPos.value = targetLeft;
  currentIndicatorWidth.value = targetWidth;
  currentScrollPos.value = scrollLeft + (currentIndex == itemWidthArr.value.length - 1 ? itemWidth : 0); 
}

watch(mersuredTabs, loadPos, { deep: true });
watch(() => props.currentIndex, loadPos);

onMounted(() => {
  nextTick(() => {
    currentCanMeasure.value = true;
    measureTab(0);
    setTimeout(() => {
      loadPos();
    }, 200);
  });
})

function onTabClick(index: number) {
  emit('click', props.tabs[index]);
  if (index !== props.currentIndex) {
    emit('update:currentIndex', index);
  }
}
</script>

<style lang="scss">
.nana-tabs {
  position: relative;
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  flex-shrink: 0;
  flex-grow: 0;
  height: auto;
  width: fit-content;
  overflow: hidden;

  .tab-item {
    position: relative;
    padding-top: 20rpx;
    padding-bottom: 30rpx;
    box-sizing: content-box;
    flex-shrink: 0;
    flex-grow: 0;
  }
  .tab-item-text {
    font-size: 15px;
  }
  .tab-indicator {
    position: absolute;
    border-radius: 3rpx;
    left: 0;
    bottom: 4rpx;
    z-index: 10;
    height: 6rpx;

    &.anim {
      transition: all 0.25s ease-in-out;
    }
  }
}
</style>