/* ============================================================================
 * 서명전에 — TDS Highlight 컴포넌트 (스포트라이트 / 코치마크)
 *  · open=true 가 되면 children 영역만 빛이 새어 나오고 화면 전체가 어두워져요.
 *  · 구현 전략: spot 에 box-shadow 0 0 0 100vmax rgba(0,0,0,.7) 로 dim 페인트
 *    + 별도 fixed 투명 backdrop 으로 외부 클릭(onClick) 캡처. 박스 섀도우는 hit-test
 *    영향이 없어 자연스럽게 동작해요.
 *  · message 는 root 기준 absolute 배치 — X 정렬은 left/center/right, Y 정렬은
 *    top(spot 위) / bottom(spot 아래). 정렬을 안 주면 spot 의 화면 위치를 보고
 *    자동 결정해요.
 *  · 화살표는 항상 spot 가로 중앙에 절대 배치 — X 정렬에 무관 (TDS 계약).
 *  · delay 는 초 단위 (TDS 스펙).
 *  · onExited 는 close → 애니메이션 종료(220ms) 후 한 번 호출.
 *
 *  · props (HighlightProps):
 *      open*                boolean — 표시 여부
 *      padding              number(px) — spot 내부 padding (기본 0)
 *      delay                number(sec) — 표시 전 지연 (기본 0)
 *      highlighterClassname string — spot 추가 className
 *      message              string | (props: { color, style }) => ReactElement
 *      messageColor         string — 메시지 색 (기본 #ffffff)
 *      messageXAlignment    "left" | "center" | "right" — 미지정 시 자동
 *      messageYAlignment    "top" | "bottom" — 미지정 시 자동
 *      onClick              (e) => void — 외부(backdrop) 클릭
 *      onExited             () => void — close 애니메이션 종료 후
 *      className, style, aria-* ...     루트 <div> 패스스루
 *      children             ReactNode — 강조될 영역
 * ========================================================================== */

const {
  useState: __hlUseState,
  useRef: __hlUseRef,
  useEffect: __hlUseEffect,
  useLayoutEffect: __hlUseLayoutEffect,
} = React;

const HIGHLIGHT_TRANSITION_MS = 220;

function Highlight({
  open = false,
  padding = 0,
  delay = 0,
  highlighterClassname = "",
  message,
  messageColor = "#ffffff",
  messageXAlignment,
  messageYAlignment,
  onClick,
  onExited,
  className = "",
  style,
  children,
  ...rest
}) {
  // visible 은 delay/transition 을 반영한 실제 화면 표시 상태.
  const [visible, setVisible] = __hlUseState(false);
  const [autoX, setAutoX] = __hlUseState("center");
  const [autoY, setAutoY] = __hlUseState("bottom");
  const spotRef = __hlUseRef(null);
  const exitedTimerRef = __hlUseRef(null);
  const enterTimerRef = __hlUseRef(null);

  // open prop 변경에 따른 visible 토글 + delay/exit 처리
  __hlUseEffect(() => {
    // 진입
    if (open) {
      // 닫힘 타이머가 떠있으면 먼저 정리
      if (exitedTimerRef.current) {
        clearTimeout(exitedTimerRef.current);
        exitedTimerRef.current = null;
      }
      if (delay > 0) {
        enterTimerRef.current = setTimeout(() => {
          setVisible(true);
          enterTimerRef.current = null;
        }, delay * 1000);
      } else {
        setVisible(true);
      }
      return () => {
        if (enterTimerRef.current) {
          clearTimeout(enterTimerRef.current);
          enterTimerRef.current = null;
        }
      };
    }
    // 닫힘
    if (enterTimerRef.current) {
      clearTimeout(enterTimerRef.current);
      enterTimerRef.current = null;
    }
    if (visible) {
      setVisible(false);
      exitedTimerRef.current = setTimeout(() => {
        onExited?.();
        exitedTimerRef.current = null;
      }, HIGHLIGHT_TRANSITION_MS + 40);
    }
    return undefined;
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [open, delay]);

  // 자동 정렬 — visible 직후 spot 위치를 보고 결정
  __hlUseLayoutEffect(() => {
    if (!visible || !spotRef.current) return;
    const r = spotRef.current.getBoundingClientRect();
    const vw =
      typeof window !== "undefined"
        ? window.innerWidth || document.documentElement.clientWidth
        : 0;
    const vh =
      typeof window !== "undefined"
        ? window.innerHeight || document.documentElement.clientHeight
        : 0;

    if (!messageXAlignment && vw > 0) {
      const cx = r.left + r.width / 2;
      if (cx < vw / 3) setAutoX("left");
      else if (cx > (vw * 2) / 3) setAutoX("right");
      else setAutoX("center");
    }
    if (!messageYAlignment && vh > 0) {
      // spot 이 화면 위쪽이면 메시지를 아래에, 아래쪽이면 위에 띄움
      setAutoY(r.top < vh / 2 ? "bottom" : "top");
    }
  }, [visible, messageXAlignment, messageYAlignment, padding]);

  const xAlign = messageXAlignment || autoX;
  const yAlign = messageYAlignment || autoY;

  // 언마운트 시 타이머 정리
  __hlUseEffect(() => {
    return () => {
      if (exitedTimerRef.current) clearTimeout(exitedTimerRef.current);
      if (enterTimerRef.current) clearTimeout(enterTimerRef.current);
    };
  }, []);

  const handleBackdropClick = (e) => {
    onClick?.(e);
  };

  // message 해석 — string 또는 함수
  let messageNode = null;
  if (message != null && message !== false) {
    const messageStyle = { color: messageColor };
    if (typeof message === "function") {
      try {
        messageNode = message({ color: messageColor, style: messageStyle });
      } catch (err) {
        if (window.console && console.warn) {
          console.warn("[Highlight] message 함수 호출 실패:", err);
        }
        messageNode = null;
      }
    } else {
      messageNode = <span style={messageStyle}>{message}</span>;
    }
  }

  const rootCls = ["tds-highlight", className].filter(Boolean).join(" ");

  const spotCls = [
    "tds-highlight__spot",
    visible ? "is-open" : "",
    highlighterClassname,
  ]
    .filter(Boolean)
    .join(" ");

  const messageCls = [
    "tds-highlight__message",
    `tds-highlight__message--x-${xAlign}`,
    `tds-highlight__message--y-${yAlign}`,
  ]
    .filter(Boolean)
    .join(" ");

  const arrowCls = [
    "tds-highlight__arrow",
    `tds-highlight__arrow--y-${yAlign}`,
  ]
    .filter(Boolean)
    .join(" ");

  return (
    <div className={rootCls} style={style} {...rest}>
      {visible && (
        <div
          className="tds-highlight__backdrop"
          onClick={handleBackdropClick}
          aria-hidden="true"
        />
      )}
      <div
        ref={spotRef}
        className={spotCls}
        style={{ padding: `${padding}px` }}
      >
        {children}
      </div>
      {visible && messageNode != null && (
        <>
          <div className={messageCls}>{messageNode}</div>
          <span
            className={arrowCls}
            style={{ color: messageColor }}
            aria-hidden="true"
          >
            <svg
              viewBox="0 0 12 8"
              width="12"
              height="8"
              focusable="false"
              aria-hidden="true"
            >
              <path d="M6 0 L12 8 L0 8 Z" fill="currentColor" />
            </svg>
          </span>
        </>
      )}
    </div>
  );
}

window.Highlight = Highlight;

Object.assign(window, { Highlight });
