/**
 * Tooltip — 文字提示气泡（Tailwind 内联）
 *
 * 默认深色变体（grey-800 背景 + 白字）；hover/focus 触发；
 * tone="light" 仅供 TagInput +N 展示更多标签等特定内容型场景使用。
 * 通过 createPortal 渲染到 document.body 以避开父容器 overflow 裁切，
 * 定位为 fixed 并随滚动/resize 同步。
 *
 * 默认开启 autoFlip：当用户指定方向上空间不足时，自动翻转到对侧主轴
 * （top↔bottom、left↔right），副轴对齐（start/center/end）保持。
 *
 * 文本容器固定规格：圆角 8px、内距上下 8px / 左右 12px、字号 14px、行高 20px。
 *
 * Props:
 *   content        — 气泡内容（string 或 ReactNode）
 *   tone           — 'dark' | 'light'，默认 'dark'
 *   placement      — 12 选其一：top/top-start/top-end/bottom/bottom-start/bottom-end/
 *                    left/left-start/left-end/right/right-start/right-end，默认 'top'
 *   arrow          — 是否显示箭头，默认 true
 *   autoFlip       — 视口边缘是否自动翻转方向，默认 true
 *   defaultOpen    — 是否默认常驻显示（用于预览/调试），默认 false
 *   mouseEnterDelay— 进入延迟（ms），默认 100
 *   mouseLeaveDelay— 离开延迟（ms），默认 100
 *   className      — 附加到气泡的类名
 *   triggerClassName — 触发器包裹层类名，默认 'inline-flex'
 *   children       — 触发器（任意 React 子节点，会被包裹到触发器容器中）
 */

import { useState, useRef, useLayoutEffect, useEffect, useId, useCallback } from 'react';
import { createPortal } from 'react-dom';
import { TFDS_Z_TOOLTIP } from '../shared/overlay-z-index';

/* ── 常量配置 ── */
const GAP = 8;            // 触发器与气泡的间距
const ARROW_W = 12;       // 箭头底边长
const ARROW_H = 6;        // 箭头高度（凸出气泡外的距离）
const SAFE_MARGIN = 4;    // 视口边缘安全距离
const ARROW_EDGE_MIN = 14; // 箭头中心距气泡边的最小距离（避开圆角）

/* ── 气泡基础样式（含固定内距/字号） ── */
const BUBBLE = [
  'pointer-events-none',
  'rounded-md',
  'whitespace-pre-line break-words',
  'max-w-[280px]',
  'font-normal',
  'px-3 py-2 text-sm leading-5',
].join(' ');

const TONE_CLASS = {
  dark: 'bg-grey-800 text-white shadow-md',
  light: 'border border-border bg-white text-foreground shadow-md',
};

const ARROW_FILL_CLASS = {
  dark: 'fill-grey-800',
  light: 'fill-white',
};

/* ── 主轴翻转映射 ── */
const FLIP_MAIN = { top: 'bottom', bottom: 'top', left: 'right', right: 'left' };

/* ── 拆解 placement → [main, side] ── */
function parsePlacement(p) {
  const [main, side] = p.split('-');
  return [main, side]; // side 可能是 undefined（即 center）
}

/* ── 计算气泡 left/top（视口坐标系） ── */
function computePosition(trigger, tw, th, placement) {
  const [main, side] = parsePlacement(placement);
  let top = 0;
  let left = 0;

  if (main === 'top') top = trigger.top - th - GAP;
  else if (main === 'bottom') top = trigger.bottom + GAP;
  else if (main === 'left') left = trigger.left - tw - GAP;
  else if (main === 'right') left = trigger.right + GAP;

  if (main === 'top' || main === 'bottom') {
    if (side === 'start') left = trigger.left;
    else if (side === 'end') left = trigger.right - tw;
    else left = trigger.left + (trigger.width - tw) / 2;
  } else {
    if (side === 'start') top = trigger.top;
    else if (side === 'end') top = trigger.bottom - th;
    else top = trigger.top + (trigger.height - th) / 2;
  }

  return { top, left };
}

/* ── 视口边缘检测，空间不足则翻转主轴 ── */
function flipPlacement(placement, trigger, tw, th, vw, vh) {
  const [main, side] = parsePlacement(placement);
  let fits = true;

  if (main === 'top') fits = trigger.top - th - GAP >= SAFE_MARGIN;
  else if (main === 'bottom') fits = trigger.bottom + th + GAP <= vh - SAFE_MARGIN;
  else if (main === 'left') fits = trigger.left - tw - GAP >= SAFE_MARGIN;
  else if (main === 'right') fits = trigger.right + tw + GAP <= vw - SAFE_MARGIN;

  if (fits) return placement;
  return side ? `${FLIP_MAIN[main]}-${side}` : FLIP_MAIN[main];
}

/* ── 计算箭头在气泡边上的偏移（从气泡左/上算起） ── */
function computeArrowOffset(actualPlacement, trigger, pos, tw, th) {
  const [main] = parsePlacement(actualPlacement);
  if (main === 'top' || main === 'bottom') {
    const triggerCenterX = trigger.left + trigger.width / 2;
    const raw = triggerCenterX - pos.left;
    return Math.max(ARROW_EDGE_MIN, Math.min(tw - ARROW_EDGE_MIN, raw));
  }
  const triggerCenterY = trigger.top + trigger.height / 2;
  const raw = triggerCenterY - pos.top;
  return Math.max(ARROW_EDGE_MIN, Math.min(th - ARROW_EDGE_MIN, raw));
}

/* ── 箭头 SVG（按主轴方向画对应朝向的三角） ── */
function ArrowSvg({ main, tone = 'dark' }) {
  const fillClass = ARROW_FILL_CLASS[tone] || ARROW_FILL_CLASS.dark;
  // 横向：底边 ARROW_W、高 ARROW_H
  if (main === 'top') {
    // tooltip 在触发器上方 → 箭头朝下
    return (
      <svg width={ARROW_W} height={ARROW_H} viewBox={`0 0 ${ARROW_W} ${ARROW_H}`} className={['block', fillClass].join(' ')} aria-hidden>
        <path d={`M0 0 L${ARROW_W} 0 L${ARROW_W / 2} ${ARROW_H} Z`} />
      </svg>
    );
  }
  if (main === 'bottom') {
    return (
      <svg width={ARROW_W} height={ARROW_H} viewBox={`0 0 ${ARROW_W} ${ARROW_H}`} className={['block', fillClass].join(' ')} aria-hidden>
        <path d={`M0 ${ARROW_H} L${ARROW_W} ${ARROW_H} L${ARROW_W / 2} 0 Z`} />
      </svg>
    );
  }
  // 纵向：宽 ARROW_H、高 ARROW_W
  if (main === 'left') {
    return (
      <svg width={ARROW_H} height={ARROW_W} viewBox={`0 0 ${ARROW_H} ${ARROW_W}`} className={['block', fillClass].join(' ')} aria-hidden>
        <path d={`M0 0 L0 ${ARROW_W} L${ARROW_H} ${ARROW_W / 2} Z`} />
      </svg>
    );
  }
  return (
    <svg width={ARROW_H} height={ARROW_W} viewBox={`0 0 ${ARROW_H} ${ARROW_W}`} className={['block', fillClass].join(' ')} aria-hidden>
      <path d={`M${ARROW_H} 0 L${ARROW_H} ${ARROW_W} L0 ${ARROW_W / 2} Z`} />
    </svg>
  );
}

export default function Tooltip({
  content,
  tone = 'dark',
  placement = 'top',
  arrow = true,
  autoFlip = true,
  defaultOpen = false,
  mouseEnterDelay = 100,
  mouseLeaveDelay = 100,
  className = '',
  triggerClassName = 'inline-flex',
  children,
}) {
  const triggerRef = useRef(null);
  const bubbleRef = useRef(null);
  const enterTimer = useRef(null);
  const leaveTimer = useRef(null);

  const [open, setOpen] = useState(defaultOpen);
  const [pos, setPos] = useState({ top: 0, left: 0, actualPlacement: placement, arrowOffset: 0 });

  const updatePosition = useCallback(() => {
    if (!triggerRef.current || !bubbleRef.current) return;
    const trigger = triggerRef.current.getBoundingClientRect();
    const bubble = bubbleRef.current.getBoundingClientRect();
    const tw = bubble.width;
    const th = bubble.height;
    const vw = window.innerWidth;
    const vh = window.innerHeight;

    const actualPlacement = autoFlip
      ? flipPlacement(placement, trigger, tw, th, vw, vh)
      : placement;
    const p = computePosition(trigger, tw, th, actualPlacement);
    const arrowOffset = computeArrowOffset(actualPlacement, trigger, p, tw, th);
    setPos({ top: p.top, left: p.left, actualPlacement, arrowOffset });
  }, [placement, autoFlip]);

  useLayoutEffect(() => {
    if (open) updatePosition();
  }, [open, content, updatePosition]);

  useEffect(() => {
    if (!open) return;
    const onScroll = () => updatePosition();
    const onResize = () => updatePosition();
    window.addEventListener('scroll', onScroll, true);
    window.addEventListener('resize', onResize);
    return () => {
      window.removeEventListener('scroll', onScroll, true);
      window.removeEventListener('resize', onResize);
    };
  }, [open, updatePosition]);

  const clearTimers = () => {
    if (enterTimer.current) clearTimeout(enterTimer.current);
    if (leaveTimer.current) clearTimeout(leaveTimer.current);
    enterTimer.current = null;
    leaveTimer.current = null;
  };

  const handleEnter = () => {
    clearTimers();
    enterTimer.current = setTimeout(() => setOpen(true), mouseEnterDelay);
  };

  const handleLeave = () => {
    clearTimers();
    leaveTimer.current = setTimeout(() => setOpen(false), mouseLeaveDelay);
  };

  useEffect(() => () => clearTimers(), []);

  const tooltipId = useId();
  const [main] = parsePlacement(pos.actualPlacement);
  const resolvedTone = TONE_CLASS[tone] ? tone : 'dark';

  /* ── 箭头容器定位（相对气泡 absolute） ── */
  let arrowStyle = {};
  if (main === 'top') {
    arrowStyle = { position: 'absolute', bottom: -ARROW_H, left: pos.arrowOffset - ARROW_W / 2 };
  } else if (main === 'bottom') {
    arrowStyle = { position: 'absolute', top: -ARROW_H, left: pos.arrowOffset - ARROW_W / 2 };
  } else if (main === 'left') {
    arrowStyle = { position: 'absolute', right: -ARROW_H, top: pos.arrowOffset - ARROW_W / 2 };
  } else {
    arrowStyle = { position: 'absolute', left: -ARROW_H, top: pos.arrowOffset - ARROW_W / 2 };
  }

  return (
    <>
      <span
        ref={triggerRef}
        className={triggerClassName}
        onMouseEnter={handleEnter}
        onMouseLeave={handleLeave}
        onFocus={handleEnter}
        onBlur={handleLeave}
        aria-describedby={open ? tooltipId : undefined}
      >
        {children}
      </span>
      {open && typeof document !== 'undefined'
        ? createPortal(
            <div
              ref={bubbleRef}
              id={tooltipId}
              role="tooltip"
              className={[`tfds-tooltip`, [BUBBLE, TONE_CLASS[resolvedTone], className].filter(Boolean).join(' ')].filter(Boolean).join(' ')}
              data-tfds-component="Tooltip"
              style={{
                position: 'fixed',
                top: pos.top,
                left: pos.left,
                zIndex: TFDS_Z_TOOLTIP,
              }}
            >
              {content}
              {arrow ? (
                <span style={arrowStyle} aria-hidden>
                  <ArrowSvg main={main} tone={resolvedTone} />
                </span>
              ) : null}
            </div>,
            document.body
          )
        : null}
    </>
  );
}
