<template>
  <div
    class="u-tabspro"
    :class="[
      `u-variant-${variant}`,
      `u-align-${align}`,
      compact ? 'u-compact' : '',
      wrap ? 'u-wrap' : 'u-nowrap'
    ]"
  >
    <div
      class="u-track"
      ref="trackRef"
      role="tablist"
      :aria-label="ariaLabel"
      @wheel.passive="onWheelScroll"
    >
      <button
        v-for="(t, i) in tabsArr"
        :key="(t.value ?? t.label ?? i) as any"
        class="u-tab"
        :class="{
          active: i === currentIndex,
          disabled: !!t.disabled,
          'u-tab--rec': isRecTab(t)              // 仅标记“推荐类”
        }"
        role="tab"
        :aria-selected="i === currentIndex"
        :tabindex="t.disabled ? -1 : (i === currentIndex ? 0 : -1)"
        :disabled="!!t.disabled"
        @click="!t.disabled && setActive(i)"
        @keydown.left.prevent="focusPrev"
        @keydown.right.prevent="focusNext"
        :ref="(el) => assignTabRef(el, i)"
      >
        <slot name="tab" :tab="t" :index="i">
          {{ t.label }}
        </slot>
      </button>

      <!-- 下划线风格：活动指示线（仅当活动且为推荐类时炫彩） -->
      <span
        v-if="variant === 'underline'"
        class="u-underline"
        :class="{ 'u-underline--rec': isActiveRec }"
        :style="{ width: underline.w + 'px', transform: `translateX(${underline.x}px)` }"
        aria-hidden="true"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import {
  ref, computed, watch, onMounted, nextTick, onBeforeUnmount,
  type ComponentPublicInstance
} from 'vue'

type Align = 'left' | 'center' | 'between'
type Variant = 'pills' | 'underline'
type TabItem = Readonly<{
  label: string
  value?: string | number
  disabled?: boolean
}>

interface Props {
  tabs: ReadonlyArray<TabItem>
  modelValue?: string | number | null
  defaultIndex?: number
  variant?: Variant
  align?: Align
  compact?: boolean
  wrap?: boolean
  ariaLabel?: string
}

const props = withDefaults(defineProps<Props>(), {
  modelValue: null,
  defaultIndex: 0,
  variant: 'pills',
  align: 'left',
  compact: false,
  wrap: true,
  ariaLabel: ''
})

const emit = defineEmits<{
  (e: 'update:modelValue', v: string | number): void
  (e: 'change', payload: { index: number; tab: TabItem }): void
}>()

const tabsArr = computed(() => props.tabs ?? [])

const tabRefs = ref<Array<HTMLButtonElement | null>>([])
function assignTabRef(
  el: Element | ComponentPublicInstance | null,
  i: number
) {
  tabRefs.value[i] = (el as HTMLButtonElement) ?? null
}

const trackRef = ref<HTMLElement | null>(null)
const currentIndex = ref(0)

function valueToIndex(v: string | number | null) {
  return tabsArr.value.findIndex(t => (t?.value ?? t?.label) === v)
}

/* -------- 推荐类判定（label/value 命中以下任一关键词即可） -------- */
function isRecTab(tab?: TabItem | null) {
  if (!tab) return false
  const raw = String(tab.value ?? tab.label ?? '').trim().toLowerCase()
  const keys = ['推荐', '精选', '热门', '置顶', 'rec']
  return keys.some(k => raw === k.toLowerCase() || raw.includes(k.toLowerCase()))
}
const isActiveRec = computed(() => isRecTab(tabsArr.value[currentIndex.value]))

/* -------- underline 位置 -------- */
const underline = ref({ x: 0, w: 0 })
function updateUnderline() {
  if (props.variant !== 'underline') return
  const el = tabRefs.value[currentIndex.value]
  const track = trackRef.value
  if (!el || !track) return
  const trackRect = track.getBoundingClientRect()
  const rect = el.getBoundingClientRect()
  underline.value = { x: rect.left - trackRect.left, w: rect.width }
}

function scrollActiveIntoView() {
  if (props.wrap) return
  const el = tabRefs.value[currentIndex.value]
  const track = trackRef.value
  if (!el || !track) return
  const padding = 24
  const left = el.offsetLeft - padding
  const right = left + el.offsetWidth + padding * 2
  if (left < track.scrollLeft) {
    track.scrollTo({ left, behavior: 'smooth' })
  } else if (right > track.scrollLeft + track.clientWidth) {
    track.scrollTo({ left: right - track.clientWidth, behavior: 'smooth' })
  }
}

function onWheelScroll(e: WheelEvent) {
  if (props.wrap) return
  const track = trackRef.value
  if (!track) return
  track.scrollLeft += e.deltaY
}

/* -------- 交互 -------- */
function setActive(i: number) {
  if (i < 0 || i >= tabsArr.value.length) return
  const tab = tabsArr.value[i]
  if (!tab || tab.disabled) return
  currentIndex.value = i
  nextTick(() => {
    updateUnderline()
    scrollActiveIntoView()
  })
  const v = (tab.value ?? tab.label) as string | number
  emit('update:modelValue', v)
  emit('change', { index: i, tab })
}

function focusPrev() {
  const len = tabsArr.value.length
  if (!len) return
  let i = (currentIndex.value - 1 + len) % len
  while (tabsArr.value[i]?.disabled && i !== currentIndex.value) {
    i = (i - 1 + len) % len
  }
  setActive(i)
  tabRefs.value[i]?.focus?.()
}
function focusNext() {
  const len = tabsArr.value.length
  if (!len) return
  let i = (currentIndex.value + 1) % len
  while (tabsArr.value[i]?.disabled && i !== currentIndex.value) {
    i = (i + 1) % len
  }
  setActive(i)
  tabRefs.value[i]?.focus?.()
}

/* -------- 同步/初始化 -------- */
watch(
  () => props.modelValue,
  (v) => {
    if (v == null) return
    const idx = valueToIndex(v)
    if (idx >= 0) {
      currentIndex.value = idx
      nextTick(() => {
        updateUnderline()
        scrollActiveIntoView()
      })
    }
  },
  { immediate: true }
)

watch(
  () => tabsArr.value.length,
  () => nextTick(updateUnderline)
)

onMounted(() => {
  if (props.modelValue == null) {
    const idx = Math.min(
      props.defaultIndex ?? 0,
      Math.max(tabsArr.value.length - 1, 0)
    )
    currentIndex.value = idx
    // 触发 update:modelValue 事件，同步父组件的状态
    const tab = tabsArr.value[idx]
    if (tab) {
      const v = (tab.value ?? tab.label) as string | number
      emit('update:modelValue', v)
    }
  }
  nextTick(() => {
    updateUnderline()
    scrollActiveIntoView()
    window.addEventListener('resize', updateUnderline)
  })
})

onBeforeUnmount(() => {
  window.removeEventListener('resize', updateUnderline)
})
</script>

<style scoped>
/* ---------- 主题变量 ---------- */
.u-tabspro {
  --gap: 12px;
  --radius: 8px;
  --font: 14px;
  --height: 30px;

  --color: #374151;       /* gray-700 */
  --muted: #6b7280;       /* gray-500 */
  --active: #111827;      /* gray-900 */
  --border: #e5e7eb;      /* gray-200 */
  --bg: #ffffff;
  --bg-muted: #f9fafb;

  /* 首页三原色系：紫 -> 靛蓝 -> 蓝 -> 青 */
  --rainbow: linear-gradient(90deg,
    #7c3aed 0%,
    #6366f1 33%,
    #60a5fa 66%,
    #22d3ee 100%);
}

/* 紧凑尺寸 */
.u-compact {
  --gap: 8px;
  --radius: 10px;
  --font: 13px;
  --height: 30px;
}

/* ---------- 布局 ---------- */
.u-track {
  display: flex;
  gap: var(--gap);
  align-items: center;
  position: relative;
  min-height: var(--height);
  width: 100%;
}

/* 排列 */
.u-align-left .u-track   { justify-content: flex-start; }
.u-align-center .u-track { justify-content: center; }
.u-align-between .u-track{ justify-content: space-between; }

/* 换行/滚动 */
.u-wrap .u-track   { flex-wrap: wrap; }
.u-nowrap .u-track { overflow-x: auto; scrollbar-width: thin; }
.u-nowrap .u-track::-webkit-scrollbar { height: 8px; }
.u-nowrap .u-track::-webkit-scrollbar-thumb {
  background: rgba(0,0,0,.12);
  border-radius: 4px;
}

/* ---------- Tab 基础 ---------- */
.u-tab {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--color);
  font-size: var(--font);
  line-height: 1;
  height: var(--height);
  padding: 0 14px;
  border-radius: var(--radius);
  cursor: pointer;
  white-space: nowrap;
  transition: all .18s ease;
  outline: none;
}
.u-tab:focus-visible {
  outline: 2px solid rgba(99,102,241,.35);
  outline-offset: 2px;
}
.u-tab.disabled {
  opacity: .45;
  cursor: not-allowed;
}

/* ---------- 变体：pills ---------- */
.u-variant-pills .u-tab { background: var(--bg-muted); }
.u-variant-pills .u-tab:hover {
  background: #eef2ff; color: var(--active);
}
.u-variant-pills .u-tab.active {
  background: var(--active); color: #fff;
  box-shadow: 0 4px 10px rgba(17,24,39,.12);
}

/* ★ 推荐：仅当选中时炫彩（整块胶囊流动） */
.u-variant-pills .u-tab.u-tab--rec.active {
  color: #fff;
  background-image: var(--rainbow);
  background-size: 220% 220%;
  animation: tabsRainbow 4s ease infinite;
  box-shadow: 0 8px 18px rgba(99,102,241,.22);
}

/* ---------- 变体：underline ---------- */
.u-variant-underline .u-track { gap: 28px; padding: 6px 2px; }
.u-variant-underline .u-tab {
  padding: 0 4px; background: transparent; border-radius: 6px; color: var(--muted);
}
.u-variant-underline .u-tab:hover { color: var(--active); }
.u-variant-underline .u-tab.active { color: var(--active); font-weight: 700; }

/* ★ 推荐：仅当选中时文字炫彩（背景裁剪到文字） */
.u-variant-underline .u-tab.u-tab--rec.active {
  background-image: var(--rainbow);
  background-size: 220% 220%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: tabsRainbow 4s ease infinite;
}

/* 指示线 */
.u-underline {
  position: absolute; bottom: 0; height: 3px; border-radius: 3px;
  background: var(--active);
  transition: transform .22s cubic-bezier(.22,1,.36,1),
              width .22s cubic-bezier(.22,1,.36,1);
  pointer-events: none;
}
/* ★ 推荐：活动且为推荐类时，指示线炫彩流动 */
.u-underline--rec {
  background-image: var(--rainbow);
  background-size: 220% 220%;
  animation: tabsRainbow 4s ease infinite;
}

/* 炫彩动画 */
@keyframes tabsRainbow {
  0%   { background-position: 0% 50%; }
  50%  { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}
</style>
