/**
 * Tabs — 同页内多块内容的视图切换
 *
 * **何时用**：详情子页签、卡片内分区、筛选维度切换（2～6 项为宜）；不改变整站路由的「面板级」导航。
 * **不用**：执行保存/取消等动作 → `Button`；单个表单字段从枚举选题 → `Select` / `Radio`；整站一级模块 → 侧栏/路由。
 *
 * **npm / AI 硬约束**：凡「点选切换多块互斥面板」**必须**用本组件；禁止一排 `Button` 或 `Tag` 冒充 Tabs。「分段器」= **`variant="segment"`**（灰轨白块），**不是** `Tag`。卡片内小模块切换、主工作区顶部**布局级**切换 → **默认优先** `variant="segment"`；详情子页签感 → `line`；强调块级 → `button`；顶导/浮层胶囊 → `pill`。
 *
 * @prop {'line'|'button'|'pill'|'segment'} [variant='line'] — line=页内主导航下划线；button/pill/segment=工具区或表单切换；segment=分段器（灰底容器+白选中块）
 * @prop {'sm'|'md'|'lg'} [size='md'] — 尺寸；如无明确要求默认 MD（与 Filter/Select 高度对齐）。需要更紧凑密度时再显式用 SM；页面级顶导可按场景用 LG
 * @prop {Array} [items=null] — 标签项列表（每项含 label，可选 icon）
 * @prop {number} [activeIndex=0] — 受控：当前选中索引
 * @prop {number} [defaultIndex=0] — 非受控初始索引
 * @prop {function} [onChange=null] — `(index) => void` 切换回调
 * @prop {boolean} [wrap=false] — 按钮/胶囊/分段器在容器较窄时换行展示全部标签；线条型保持单行横滑
 * @prop {boolean} [wrapFill=false] — 与 wrap 联用：true 时每行 flex-1 撑满容器宽度；false 时仅换行、标签保持自然宽度
 * @prop {string} [className=''] — 根节点类名
 */
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import Button from './Button';
import Icon from './Icon';

/* ── 容器样式 ── */
const VIEWPORT_BASE = 'tfds-tabs relative block max-w-full min-w-0';
const VIEWPORT_SCROLL = [
  'overflow-x-auto overflow-y-hidden overscroll-x-contain',
  '[scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden',
].join(' ');

const CONTAINER_BASE = 'inline-flex w-max max-w-none items-center relative';
const CONTAINER_WRAP = 'relative flex w-full max-w-full flex-wrap';
const CONTAINER_WRAP_NATURAL = 'inline-flex max-w-full flex-wrap items-center relative';

const CONTAINER_VARIANT = {
  line:    'gap-2 bg-transparent border-b border-b-border',
  button:  'gap-2 bg-transparent',
  // pill 容器用 ring-inset 替代 border，避免 border 撑高 2px，让"容器高度 = padding 上下 + 选项高度"
  // 圆角见 PILL_CONTAINER_RADIUS（单行全圆角 / 多行大圆角）
  pill:    'gap-1 bg-white/50 ring-1 ring-white ring-inset',
  // 分段器容器 padding 由 size 控制：SM=2px（p-0.5），MD/LG=4px（p-1）
  segment: 'gap-0.5 bg-fill rounded-md',
};

/* ── 胶囊容器圆角：单行保持全圆角；wrap 多行时改大圆角，避免与选项全圆角叠压 ── */
const PILL_CONTAINER_RADIUS = {
  single: 'rounded-full',
  wrap: 'rounded-2xl', // 16px，多行块级容器的半圆角
};

/* ── 胶囊容器内距（pill × size → padding）── */
const PILL_CONTAINER_PADDING = {
  // 胶囊容器四周 padding 统一：4px（便于对齐多 Tabs 溢出场景的视觉留白）
  sm: 'p-1', // 4px
  // MD 总高对齐 36px：容器 padding=4px×2，item=28px
  md: 'p-1', // 4px
  lg: 'p-1.5', // 6px（对应总高 48px）
};

/* ── 分段器容器内距（segment × size → padding）── */
const SEGMENT_CONTAINER_PADDING = {
  sm: 'p-0.5', // 2px
  md: 'p-1',   // 4px
  lg: 'p-1',   // 4px
};

/* ── 标签项基础样式（所有变体共用的结构属性） ── */
/** 选中 / 未选中字重一致，避免切换时宽度抖动 */
const TAB_ITEM_FONT_WEIGHT = '[font-weight:var(--font-medium)]';

const ITEM_BASE = [
  'inline-flex items-center justify-center relative',
  'border-none cursor-pointer select-none',
  '[font-family:inherit]',
  TAB_ITEM_FONT_WEIGHT,
  'leading-[20px] whitespace-nowrap',
  'gap-2',
  '[outline:2px_solid_transparent] outline-offset-2',
  'transition-[color,background-color,box-shadow] tfds-motion-ui-normal',
].join(' ');

/* ── 滑动指示器（line 下划线 / 其余变体滑块）── */
const LINE_INDICATOR = [
  'pointer-events-none absolute -bottom-px left-0 z-[1] h-[3px] bg-brand-500',
  'transition-[left,width] tfds-motion-ui-normal',
].join(' ');
const BUTTON_THUMB = [
  'pointer-events-none absolute left-0 top-0 z-0 rounded-md bg-brand-50',
  'transition-[left,width,top,height] tfds-motion-ui-normal',
].join(' ');
const PILL_THUMB = [
  'pointer-events-none absolute left-0 top-0 z-0 rounded-full bg-grey-950',
  'transition-[left,width,top,height] tfds-motion-ui-normal',
].join(' ');
const SEGMENT_THUMB = [
  'pointer-events-none absolute left-0 top-0 z-0 rounded-md bg-white',
  'transition-[left,width,top,height] tfds-motion-ui-normal',
].join(' ');

const SLIDING_INDICATOR_CLASS = {
  line: LINE_INDICATOR,
  button: BUTTON_THUMB,
  pill: PILL_THUMB,
  segment: SEGMENT_THUMB,
};

/* ── 标签项变体样式（default = 未选中，active = 选中） ── */
const ITEM_VARIANT = {
  line: {
    default: 'text-blueGrey-600 hover:text-blueGrey-700 active:text-blueGrey-800 focus-visible:outline-brand-200',
    active:  'text-blueGrey-900 hover:text-blueGrey-900 focus-visible:outline-brand-200',
  },
  button: {
    default: 'z-[1] text-blueGrey-600 rounded-md hover:bg-fill hover:text-blueGrey-700 active:bg-blueGrey-200 focus-visible:outline-brand-200',
    active:  'z-[1] text-brand-700 rounded-md hover:text-brand-700 active:text-brand-700 focus-visible:outline-brand-200',
  },
  pill: {
    default: 'z-[1] text-blueGrey-700 rounded-full hover:bg-fill active:bg-blueGrey-300 focus-visible:outline-blueGrey-400',
    active:  'z-[1] text-white rounded-full hover:text-white active:text-white focus-visible:outline-grey-400',
  },
  segment: {
    default: 'z-[1] text-blueGrey-600 rounded-md hover:text-blueGrey-700 hover:bg-fill active:bg-white/70 focus-visible:outline-blueGrey-400',
    active:  'z-[1] text-blueGrey-900 rounded-md hover:text-blueGrey-900 active:text-blueGrey-900 focus-visible:outline-blueGrey-400',
  },
};

/* ── 标签项尺寸样式（variant × size → height + padding + font-size） ── */
const ITEM_SIZE = {
  line: {
    sm: 'h-[38px] px-3 text-xs [font-size:var(--text-xs)] leading-[var(--leading-4)]',
    md: 'h-[46px] px-3 text-sm [font-size:var(--text-sm)] leading-[var(--leading-5)]',
    lg: 'h-[54px] px-4 text-sm [font-size:var(--text-sm)] leading-[var(--leading-5)]',
  },
  button: {
    sm: 'h-[32px] px-3 text-xs [font-size:var(--text-xs)] leading-[var(--leading-4)]',
    md: 'h-[36px] px-3 text-sm [font-size:var(--text-sm)] leading-[var(--leading-5)]',
    lg: 'h-[40px] px-4 text-sm [font-size:var(--text-sm)] leading-[var(--leading-5)]',
  },
  pill: {
    sm: 'h-[28px] px-4 text-xs [font-size:var(--text-xs)] leading-[var(--leading-4)]',
    // MD 总高对齐 36px：容器 padding=4px×2，item=28px
    md: 'h-[28px] px-4 text-sm [font-size:var(--text-sm)] leading-[var(--leading-5)]',
    lg: 'h-[36px] px-5 text-sm [font-size:var(--text-sm)] leading-[var(--leading-5)]',
  },
  segment: {
    xs: 'h-[24px] px-2 text-xs [font-size:var(--text-xs)] leading-[var(--leading-4)]',
    sm: 'h-[28px] px-3 text-xs [font-size:var(--text-xs)] leading-[var(--leading-4)]',
    // MD 总高对齐 36px：容器 padding=4px×2，item=28px
    md: 'h-[28px] px-3 text-sm [font-size:var(--text-sm)] leading-[var(--leading-5)]',
    lg: 'h-[36px] px-4 text-sm [font-size:var(--text-sm)] leading-[var(--leading-5)]',
  },
};

/* ── 图标插槽 ── */
const ICON_CLASS = 'flex items-center justify-center shrink-0 w-4 h-4';
const ITEM_WRAP = 'flex-1 min-w-[92px]';

/* ── 多 Tabs 溢出适配：左右内联滚动按钮（占位布局，不悬浮覆盖标签） ── */
const ROOT_INLINE_NAV = 'tfds-tabs flex w-full max-w-full min-w-0 items-center gap-1';
const SCROLL_STRIP = [
  'flex-1 min-w-0 relative',
  'overflow-x-auto overflow-y-hidden overscroll-x-contain',
  '[scrollbar-width:none] [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden',
].join(' ');
export default function Tabs({
  variant = 'line',
  size = 'md',
  items = null,
  activeIndex,
  defaultIndex = 0,
  onChange,
  wrap = false,
  wrapFill = false,
  className = '',
  ...rest
}) {
  const viewportRef = useRef(null);
  const containerRef = useRef(null);
  const tabRefs = useRef([]);
  const [indicatorStyle, setIndicatorStyle] = useState({ opacity: 0 });
  const [internalIndex, setInternalIndex] = useState(defaultIndex);
  const isControlled = activeIndex !== undefined;
  const currentIndex = isControlled ? (activeIndex ?? 0) : internalIndex;
  const tabs = items ?? [];
  const [scrollState, setScrollState] = useState({ hasOverflow: false, canLeft: false, canRight: false });

  const isScrollable = !wrap;

  const updateIndicator = useCallback(() => {
    const container = containerRef.current;
    const activeTab = tabRefs.current[currentIndex];
    if (!container || !activeTab) return;

    const containerRect = container.getBoundingClientRect();
    const tabRect = activeTab.getBoundingClientRect();
    setIndicatorStyle({
      left: tabRect.left - containerRect.left,
      top: tabRect.top - containerRect.top,
      width: tabRect.width,
      height: variant === 'line' ? undefined : tabRect.height,
      opacity: 1,
    });
  }, [currentIndex, variant]);

  useEffect(() => {
    tabRefs.current = tabRefs.current.slice(0, tabs.length);
  }, [tabs.length]);

  useEffect(() => {
    const frameId = requestAnimationFrame(updateIndicator);

    const container = containerRef.current;
    const scrollParent = viewportRef.current;
    const observer = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(updateIndicator) : null;
    if (container) observer?.observe(container);
    const activeTab = tabRefs.current[currentIndex];
    if (activeTab) observer?.observe(activeTab);

    scrollParent?.addEventListener('scroll', updateIndicator, { passive: true });
    window.addEventListener('resize', updateIndicator);

    return () => {
      cancelAnimationFrame(frameId);
      observer?.disconnect();
      scrollParent?.removeEventListener('scroll', updateIndicator);
      window.removeEventListener('resize', updateIndicator);
    };
  }, [currentIndex, tabs.length, updateIndicator]);

  const scrollToSide = (dir) => {
    const el = viewportRef.current;
    if (!el) return;
    const delta = Math.max(120, Math.floor(el.clientWidth * 0.8));
    el.scrollBy({ left: dir === 'left' ? -delta : delta, behavior: 'smooth' });
  };

  const updateScrollState = useMemo(() => {
    return () => {
      const el = viewportRef.current;
      if (!el) return;
      const maxScrollLeft = el.scrollWidth - el.clientWidth;
      if (maxScrollLeft <= 1) {
        setScrollState({ hasOverflow: false, canLeft: false, canRight: false });
        return;
      }
      setScrollState({
        hasOverflow: true,
        canLeft: el.scrollLeft > 1,
        canRight: el.scrollLeft < maxScrollLeft - 1,
      });
    };
  }, []);

  useEffect(() => {
    if (!isScrollable) return undefined;
    updateScrollState();
    const el = viewportRef.current;
    if (!el) return undefined;

    const onScroll = () => updateScrollState();
    el.addEventListener('scroll', onScroll, { passive: true });

    const observer = typeof ResizeObserver !== 'undefined'
      ? new ResizeObserver(updateScrollState)
      : null;
    observer?.observe(el);

    window.addEventListener('resize', updateScrollState);
    return () => {
      el.removeEventListener('scroll', onScroll);
      observer?.disconnect();
      window.removeEventListener('resize', updateScrollState);
    };
  }, [isScrollable, tabs.length, updateScrollState]);

  const handleClick = (index) => {
    if (!isControlled) setInternalIndex(index);
    onChange?.(index);
  };

  const handleKeyDown = (event) => {
    const lastIndex = tabs.length - 1;
    if (lastIndex < 0) return;

    const nextIndexMap = {
      ArrowRight: Math.min(currentIndex + 1, lastIndex),
      ArrowLeft: Math.max(currentIndex - 1, 0),
      Home: 0,
      End: lastIndex,
    };
    const nextIndex = nextIndexMap[event.key];
    if (nextIndex === undefined || nextIndex === currentIndex) return;

    event.preventDefault();
    handleClick(nextIndex);
    event.currentTarget.querySelectorAll('[role="tab"]')[nextIndex]?.focus();
  };

  const showInlineNav = isScrollable && scrollState.hasOverflow;
  const lineBorderOnRoot = variant === 'line' && showInlineNav;

  const containerCls = [
    wrap ? (wrapFill ? CONTAINER_WRAP : CONTAINER_WRAP_NATURAL) : CONTAINER_BASE,
    variant === 'line'
      ? (lineBorderOnRoot ? 'gap-2 bg-transparent' : CONTAINER_VARIANT.line)
      : CONTAINER_VARIANT[variant],
    variant === 'pill'
      ? [
          wrap && wrapFill ? PILL_CONTAINER_RADIUS.wrap : PILL_CONTAINER_RADIUS.single,
          PILL_CONTAINER_PADDING[size] || PILL_CONTAINER_PADDING.sm,
        ].join(' ')
      : '',
    variant === 'segment' ? (SEGMENT_CONTAINER_PADDING[size] || SEGMENT_CONTAINER_PADDING.sm) : '',
  ].filter(Boolean).join(' ');

  const viewportCls = [
    VIEWPORT_BASE,
    wrap ? 'w-full overflow-visible' : VIEWPORT_SCROLL,
    !showInlineNav ? className : '',
  ].filter(Boolean).join(' ');

  const rootInlineCls = [
    ROOT_INLINE_NAV,
    lineBorderOnRoot ? 'border-b border-b-border' : '',
    className,
  ].filter(Boolean).join(' ');

  const tabButtons = tabs.map((item, index) => {
        const isActive = index === currentIndex;
        const itemCls = [
          ITEM_BASE,
          ITEM_VARIANT[variant][isActive ? 'active' : 'default'],
          ITEM_SIZE[variant][size],
          wrap && wrapFill && variant !== 'line' ? ITEM_WRAP : '',
        ].filter(Boolean).join(' ');
    return (
      <button
        key={index}
        ref={(node) => {
          tabRefs.current[index] = node;
        }}
        className={itemCls}
        role="tab"
        aria-selected={isActive}
        tabIndex={isActive ? 0 : -1}
        onClick={() => handleClick(index)}
      >
        {item.icon && <span className={ICON_CLASS}>{item.icon}</span>}
        {item.label}
      </button>
    );
  });

  const tabList = (
    <div className={containerCls} ref={containerRef}>
      {indicatorStyle.opacity ? (
        <span
          aria-hidden="true"
          className={SLIDING_INDICATOR_CLASS[variant]}
          style={{
            left: indicatorStyle.left,
            top: variant === 'line' ? undefined : indicatorStyle.top,
            width: indicatorStyle.width,
            height: variant === 'line' ? undefined : indicatorStyle.height,
          }}
        />
      ) : null}
      {tabButtons}
    </div>
  );

  const scrollBtn = (dir) => (
    <Button
      variant="ghost-black"
      size="sm"
      iconOnly
      className="shrink-0 h-7 w-7"
      icon={(
        <Icon
          name={dir === 'left' ? 'chevron-left-stroked' : 'chevron-right-stroked'}
          size={16}
          aria-hidden="true"
        />
      )}
      aria-label={dir === 'left' ? '向左滚动标签' : '向右滚动标签'}
      disabled={dir === 'left' ? !scrollState.canLeft : !scrollState.canRight}
      onClick={() => scrollToSide(dir)}
      tabIndex={-1}
    />
  );

  if (showInlineNav) {
    return (
      <div
        className={rootInlineCls}
        data-tfds-component="Tabs"
        {...rest}
      >
        {scrollBtn('left')}
        <div
          className={SCROLL_STRIP}
          ref={viewportRef}
          role="tablist"
          onKeyDown={handleKeyDown}
        >
          {tabList}
        </div>
        {scrollBtn('right')}
      </div>
    );
  }

  return (
    <div
      className={viewportCls}
      ref={viewportRef}
      role="tablist"
      onKeyDown={handleKeyDown}
      {...rest}
      data-tfds-component="Tabs"
    >
      {tabList}
    </div>
  );
}
