/* ============================================================================
 * 서명전에 — TDS Skeleton 컴포넌트
 *  · 데이터 로딩 중 콘텐츠의 기본 레이아웃을 임시로 보여 주는 컴포넌트.
 *
 *  · 두 가지 사용 방식:
 *      pattern  — 미리 정의된 9 개 패턴 중 선택 (기본 "topList")
 *      custom   — 자유롭게 조립한 타입 배열 (있으면 pattern 무시)
 *
 *  · 9 개 프리셋 패턴 → 내부 시퀀스:
 *      topList                  → ["title", "list"]
 *      topListWithIcon          → ["title", "listWithIcon"]
 *      amountTopList            → ["title", "subtitle", "list"]
 *      amountTopListWithIcon    → ["title", "subtitle", "listWithIcon"]
 *      subtitleList             → ["subtitle", "list"]
 *      subtitleListWithIcon     → ["subtitle", "listWithIcon"]
 *      listOnly                 → ["list"]
 *      listWithIconOnly         → ["listWithIcon"]
 *      cardOnly                 → ["card"]
 *
 *  · custom 가능한 타입:
 *      "title"        — 굵고 큰 바 (24px)
 *      "subtitle"     — 얇은 바 (16px)
 *      "list"         — 가로형 바 2 줄
 *      "listWithIcon" — 좌측 40px 원형 + 우측 바 2 줄
 *      "card"         — 직사각형 블록 (120px)
 *      "spacer(NN)"   — NN 픽셀 빈 공간 (예: "spacer(20)")
 *
 *  · repeatLastItemCount: number | "infinite"
 *      - 기본 3 — 마지막 요소가 총 3 번 반복돼요.
 *      - "infinite" — 30 회로 캡 (성능 보호).
 *      - 숫자 범위 외(0 이하/30 초과/소수)는 [1, 30] 으로 클램프.
 *
 *  · play: "show" | "hide"
 *      - hide → 컴포넌트 자체가 렌더되지 않음 (return null).
 *
 *  · background: "white" | "grey" | "greyOpacity100"
 *      - 시각적 바(bar/icon/card) 의 색을 결정.
 *      - 컨테이너 배경은 transparent — 부모의 배경에 자연스럽게 얹힘.
 *      - white: 어두운 부모용  /  grey(기본): 일반  /  greyOpacity100: 진한 회색.
 *
 *  · 접근성:
 *      role="status" + aria-busy="true" + aria-live="polite"
 *      + aria-label="콘텐츠 로딩 중" (외부에서 aria-label 오버라이드 가능)
 * ========================================================================== */

const __SKELETON_PATTERNS = {
  topList:               ["title", "list"],
  topListWithIcon:       ["title", "listWithIcon"],
  amountTopList:         ["title", "subtitle", "list"],
  amountTopListWithIcon: ["title", "subtitle", "listWithIcon"],
  subtitleList:          ["subtitle", "list"],
  subtitleListWithIcon:  ["subtitle", "listWithIcon"],
  listOnly:              ["list"],
  listWithIconOnly:      ["listWithIcon"],
  cardOnly:              ["card"],
};

const __SKELETON_BG_CLASS = {
  white:           "tds-skeleton--bg-white",
  grey:            "tds-skeleton--bg-grey",
  greyOpacity100:  "tds-skeleton--bg-grey-opacity-100",
};

const __SKELETON_PLAY  = { show: 1, hide: 1 };
const __SKELETON_TYPES = {
  title: 1, subtitle: 1, list: 1, listWithIcon: 1, card: 1,
};

const __SKELETON_SPACER_RE = /^spacer\((\d+)\)$/;

function __isSkeletonSpacer(t) {
  return typeof t === "string" && __SKELETON_SPACER_RE.test(t);
}
function __getSkeletonSpacerSize(t) {
  const m = __SKELETON_SPACER_RE.exec(t);
  return m ? parseInt(m[1], 10) : 0;
}

// ----- 단일 아이템 렌더 -----
function __renderSkeletonItem(type, key) {
  if (__isSkeletonSpacer(type)) {
    const n = __getSkeletonSpacerSize(type);
    return (
      <div
        key={key}
        className="tds-skeleton__spacer"
        style={{ height: `${n}px` }}
        aria-hidden="true"
      />
    );
  }
  switch (type) {
    case "title":
      return (
        <div key={key} className="tds-skeleton__bar tds-skeleton__bar--title" />
      );
    case "subtitle":
      return (
        <div key={key} className="tds-skeleton__bar tds-skeleton__bar--subtitle" />
      );
    case "list":
      return (
        <div key={key} className="tds-skeleton__list">
          <div className="tds-skeleton__bar tds-skeleton__bar--list-1" />
          <div className="tds-skeleton__bar tds-skeleton__bar--list-2" />
        </div>
      );
    case "listWithIcon":
      return (
        <div key={key} className="tds-skeleton__list-with-icon">
          <div className="tds-skeleton__icon" />
          <div className="tds-skeleton__list-text">
            <div className="tds-skeleton__bar tds-skeleton__bar--list-1" />
            <div className="tds-skeleton__bar tds-skeleton__bar--list-2" />
          </div>
        </div>
      );
    case "card":
      return <div key={key} className="tds-skeleton__card" />;
    default:
      return null;
  }
}

function Skeleton({
  height = "auto",
  pattern = "topList",
  custom,
  repeatLastItemCount = 3,
  play = "show",
  background = "grey",
  className = "",
  style,
  id,
  "aria-label": ariaLabel,
  ...rest
}) {
  // ----- play 검증 + hide 시 즉시 unmount -----
  if (!__SKELETON_PLAY[play]) {
    if (window.console && console.warn) {
      console.warn(
        `[Skeleton] play 는 "show" | "hide" 만 가능해요. 받은 값: ${play}`
      );
    }
  }
  if (play === "hide") return null;

  // ----- 시퀀스 결정: custom 우선, 없으면 pattern -----
  const usingCustom = Array.isArray(custom) && custom.length > 0;
  let sequence;
  if (usingCustom) {
    // 알 수 없는 타입은 거르고 콘솔 경고
    sequence = custom.filter(function (t) {
      const ok = (typeof t === "string" && __SKELETON_TYPES[t]) || __isSkeletonSpacer(t);
      if (!ok && window.console && console.warn) {
        console.warn(
          `[Skeleton] custom 의 알 수 없는 타입: ${JSON.stringify(t)}. ` +
          `허용: title / subtitle / list / listWithIcon / card / spacer(NN)`
        );
      }
      return ok;
    });
  } else {
    if (!__SKELETON_PATTERNS[pattern]) {
      if (window.console && console.warn) {
        console.warn(
          `[Skeleton] 알 수 없는 pattern: "${pattern}". 'topList' 로 대체해요.`
        );
      }
    }
    sequence = __SKELETON_PATTERNS[pattern] || __SKELETON_PATTERNS.topList;
  }

  if (!sequence || sequence.length === 0) return null;

  // ----- 반복 횟수 결정 -----
  let repeatN;
  if (repeatLastItemCount === "infinite") {
    repeatN = 30;
  } else if (
    typeof repeatLastItemCount === "number" &&
    isFinite(repeatLastItemCount)
  ) {
    repeatN = Math.max(1, Math.min(30, Math.floor(repeatLastItemCount)));
  } else {
    if (
      repeatLastItemCount !== undefined &&
      repeatLastItemCount !== null &&
      window.console &&
      console.warn
    ) {
      console.warn(
        `[Skeleton] repeatLastItemCount 는 number 또는 "infinite" 여야 해요. ` +
        `받은 값: ${JSON.stringify(repeatLastItemCount)}. 기본값 3 사용.`
      );
    }
    repeatN = 3;
  }

  // ----- 마지막 요소 반복 — [...앞부분, 마지막 × N] -----
  // 마지막은 spacer 가 아닌 시각 요소여야 함. spacer 면 그 앞의 시각 요소를 반복.
  let lastIdx = sequence.length - 1;
  while (lastIdx >= 0 && __isSkeletonSpacer(sequence[lastIdx])) {
    lastIdx -= 1;
  }
  if (lastIdx < 0) {
    // 전부 spacer 면 그대로 한 번만 렌더 (반복 의미 없음)
    return __renderSkeletonRoot({
      cls: __buildSkeletonCls(background, className),
      style: __buildSkeletonStyle(height, style),
      id,
      ariaLabel,
      restProps: rest,
      children: sequence.map(function (t, i) {
        return __renderSkeletonItem(t, i);
      }),
    });
  }

  const lastItem = sequence[lastIdx];
  const beforeLast = sequence.slice(0, lastIdx);
  const afterLastSpacers = sequence.slice(lastIdx + 1); // 마지막 뒤 spacer 들 (있다면)

  const finalItems = beforeLast.slice();
  for (let i = 0; i < repeatN; i++) {
    finalItems.push(lastItem);
    // 반복 사이에 원래 마지막 뒤 spacer 가 있었으면 사이에 끼움
    if (afterLastSpacers.length > 0 && i < repeatN - 1) {
      for (let j = 0; j < afterLastSpacers.length; j++) {
        finalItems.push(afterLastSpacers[j]);
      }
    }
  }

  return __renderSkeletonRoot({
    cls: __buildSkeletonCls(background, className),
    style: __buildSkeletonStyle(height, style),
    id,
    ariaLabel,
    restProps: rest,
    children: finalItems.map(function (t, i) {
      return __renderSkeletonItem(t, i);
    }),
  });
}

// ----- 헬퍼: root wrapper 렌더 -----
function __renderSkeletonRoot({ cls, style, id, ariaLabel, restProps, children }) {
  return (
    <div
      id={id}
      className={cls}
      style={style}
      role="status"
      aria-busy="true"
      aria-live="polite"
      aria-label={ariaLabel != null ? ariaLabel : "콘텐츠 로딩 중"}
      {...restProps}
    >
      {children}
    </div>
  );
}

function __buildSkeletonCls(background, className) {
  if (!__SKELETON_BG_CLASS[background] && window.console && console.warn) {
    console.warn(
      `[Skeleton] background 는 "white" | "grey" | "greyOpacity100" 만 가능해요. ` +
      `받은 값: ${background}. 'grey' 사용.`
    );
  }
  const bgCls = __SKELETON_BG_CLASS[background] || __SKELETON_BG_CLASS.grey;
  return ["tds-skeleton", bgCls, className].filter(Boolean).join(" ");
}

function __buildSkeletonStyle(height, style) {
  const out = style ? { ...style } : {};
  if (height !== undefined && height !== null && height !== "auto") {
    out.height = typeof height === "number" ? `${height}px` : height;
  }
  return out;
}

window.Skeleton = Skeleton;
Object.assign(window, { Skeleton });
