/* ============================================================================
 * 서명전에 — TDS NumberKeypad 컴포넌트
 *  · 숫자만 입력받는 커스텀 키패드. PIN · 주민등록번호 뒷자리 · 카드번호 등
 *    보안이 중요한 수치 입력에 사용해요.
 *  · 기본 배치는 3×4 격자:
 *        [1 2 3]
 *        [4 5 6]
 *        [7 8 9]
 *        [ _  0  ⌫ ]
 *    숫자 배열은 `numbers` prop 으로 재배치 가능 — 기본 [1,2,3,4,5,6,7,8,9,0].
 *    길이는 반드시 10 이어야 해요. 10이 아니면 경고 후 기본값으로 fallback.
 *
 *  · 보안 모드 (`secure = true`):
 *      - 사용자가 키를 눌렀을 때 실제 값 외에 **유령 키 이벤트 2회** 를
 *        추가 발송해 키로거 측면채널 공격을 방해해요.
 *      - 유령 키는 눌린 키의 상/하/좌/우 인접칸을 제외한 나머지 숫자 중에서
 *        난수로 2개 선택해 `onKeyClick(value, { ghost: true })` 로 통지.
 *      - 실제 값은 `onKeyClick(value, { ghost: false })`. 호출 순서는
 *        "실제값 먼저, 유령 2회 뒤" 로 고정해 호출부가 첫 번째 이벤트만
 *        신뢰하면 되도록 했어요.
 *      - 호출부에서 구분하지 않으려면 `onSecureKey(value)` 콜백을 쓰세요.
 *        이 콜백은 실제 키 한 번만 호출돼요.
 *
 *  · 시각 스펙 (TDS NumberKeypad 2026-03):
 *      - 3열 × 4행 격자, 각 셀 높이 56px, hairline `--tds-grey-opacity-200`
 *      - 배경 `var(--bg-default)` = 흰색, 누름 시 `--tds-grey-100`
 *      - 글자 `var(--label)` (grey-900), 타이포 `--ty-4` + bold
 *      - Backspace 아이콘 24px mono, `--label` 컬러
 *
 *  · props (NumberKeypadProps):
 *      numbers?             number[] | string[]  길이 10, 기본 [1..9,0]
 *      secure?              boolean — 유령 키 이벤트 활성 (기본 false)
 *      onKeyClick*          (value, meta) => void
 *                             meta = { ghost: boolean }
 *                             secure=false 면 meta.ghost 는 항상 false.
 *      onSecureKey?         (value) => void  — 실제 키 한 번만 받고 싶을 때
 *      onBackspaceClick*    () => void
 *      disabled?            boolean — 전체 비활성 (기본 false)
 *      backspaceAriaLabel?  string  — 기본 "한 글자 지우기"
 *      className, style     — 컨테이너 속성 패스스루
 *
 *  · 접근성:
 *      - 각 숫자 키는 `<button>` + aria-label=숫자
 *      - Backspace 는 기본 aria-label="한 글자 지우기"
 *      - 빈 패딩 셀은 aria-hidden="true"
 *      - secure 모드여도 실제 사용자 입력만 aria-live 값에 반영되도록
 *        유령 이벤트에는 `meta.ghost = true` 로 마킹 — 호출부 책임
 *
 *  · 웹 환경 한계 (매우 중요):
 *      - TDS native NumberKeypad 는 secure 모드에서 iOS 백그라운드 전환 시
 *        앱 화면을 가려(blur) 스냅샷에 계좌번호·비밀번호가 남지 않게 막고,
 *        Android 는 FLAG_SECURE 를 걸어 화면 녹화/캡처를 차단해요.
 *      - 우리 앱은 **웹뷰 기반 앱인토스 환경** 이라 두 방어 모두 웹 레이어에서
 *        직접 적용할 수 없어요. 같은 목적을 달성하려면 Toss 네이티브 쪽에
 *        「민감 입력 화면 보호」 플래그를 요청해야 해요 — 후속 과제.
 *      - 따라서 **웹에서 secure=true 는 유령 키 난독만 담당** 한다는 점을
 *        개발자 문서(TDS_GUIDE §4.44)에 명시해 두었어요.
 *
 *  · 호환:
 *      - Babel Standalone 글로벌 스코프 충돌 방지를 위해 React 훅은
 *        쓰지 않아요 (상태 없는 순수 컴포넌트).
 *      - window.NumberKeypad 로 글로벌 등록.
 * ========================================================================== */

const _DEFAULT_NUMBERS = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];

/* Backspace SVG — AlphabetKeypad 와 동일 규격 (24×24 currentColor mono) */
function _NumberKeypadBackspaceIcon() {
  return (
    <svg
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      aria-hidden="true"
    >
      <path
        d="M8.4 5.5h10.85c.97 0 1.75.78 1.75 1.75v9.5c0 .97-.78 1.75-1.75 1.75H8.4a1.75 1.75 0 0 1-1.39-.68L3 12l4.01-5.82A1.75 1.75 0 0 1 8.4 5.5Z"
        stroke="currentColor"
        strokeWidth="1.6"
        strokeLinejoin="round"
      />
      <path
        d="m11.3 9.6 4.9 4.9m0-4.9-4.9 4.9"
        stroke="currentColor"
        strokeWidth="1.6"
        strokeLinecap="round"
      />
    </svg>
  );
}

/* 유령 키 후보 계산
 *  · 기본 레이아웃 기준 인접(Manhattan distance = 1) 셀을 제외한
 *    나머지 숫자들 중 난수 2개 반환.
 *  · `numbers` 배열은 격자 순서 — 인덱스 0..8 은 (row, col) = (i/3, i%3),
 *    인덱스 9 (기본 "0") 은 마지막 행 가운데(row=3, col=1) 고정.
 *  · 인덱스 9 가 존재하지 않는 배열 길이일 땐 호출되기 전에 방어됨 (기본값 fallback).
 */
function _numkeypadAdjacencyIndex(idx) {
  // 12셀 격자: 0..8 = 1..9, 9 번째 아이템은 (row=3, col=1) 슬롯.
  if (idx === 9) return { row: 3, col: 1 };
  return { row: Math.floor(idx / 3), col: idx % 3 };
}

function _numkeypadPickGhostIndices(pressedIdx, total) {
  const pressedPos = _numkeypadAdjacencyIndex(pressedIdx);
  const candidates = [];
  for (let i = 0; i < total; i += 1) {
    if (i === pressedIdx) continue;
    const p = _numkeypadAdjacencyIndex(i);
    const dist = Math.abs(p.row - pressedPos.row) + Math.abs(p.col - pressedPos.col);
    if (dist <= 1) continue; // 인접 셀 제외
    candidates.push(i);
  }
  // 후보가 2개 미만이면(이론상 없음) 가능한 만큼만 반환
  const picks = [];
  const pool = candidates.slice();
  const want = Math.min(2, pool.length);
  for (let i = 0; i < want; i += 1) {
    const r = Math.floor(Math.random() * pool.length);
    picks.push(pool[r]);
    pool.splice(r, 1);
  }
  return picks;
}

function NumberKeypad({
  numbers,
  secure = false,
  onKeyClick,
  onSecureKey,
  onBackspaceClick,
  disabled = false,
  backspaceAriaLabel = "한 글자 지우기",
  className = "",
  style,
  ...rest
}) {
  // 콜백 누락 경고
  if (typeof onKeyClick !== "function" && typeof onSecureKey !== "function") {
    if (window.console && console.warn) {
      console.warn(
        "[NumberKeypad] `onKeyClick` 또는 `onSecureKey` 중 하나는 필수예요. 숫자 키 핸들러를 넘겨주세요."
      );
    }
  }
  if (typeof onBackspaceClick !== "function") {
    if (window.console && console.warn) {
      console.warn(
        "[NumberKeypad] `onBackspaceClick` 은 필수예요. 지우기 핸들러를 넘겨주세요."
      );
    }
  }

  // numbers 배열은 길이 10 이어야 해요. 아니면 기본값 사용 + 경고.
  let keys = _DEFAULT_NUMBERS;
  if (Array.isArray(numbers)) {
    if (numbers.length === 10) {
      keys = numbers.slice();
    } else if (window.console && console.warn) {
      console.warn(
        "[NumberKeypad] `numbers` 는 길이 10 이어야 해요. 기본 [1..9,0] 으로 대체돼요.",
        { received: numbers.length }
      );
    }
  }

  const handlePress = (idx) => {
    if (disabled) return;
    const value = keys[idx];

    // 실제 키 이벤트 먼저
    if (typeof onKeyClick === "function") {
      try {
        onKeyClick(value, { ghost: false });
      } catch (e) {
        if (window.console && console.error) console.error("[NumberKeypad] onKeyClick threw:", e);
      }
    }
    if (typeof onSecureKey === "function") {
      try {
        onSecureKey(value);
      } catch (e) {
        if (window.console && console.error) console.error("[NumberKeypad] onSecureKey threw:", e);
      }
    }

    // secure 모드: 유령 키 2개 추가 — onKeyClick 에만 통지 (onSecureKey 는 실제 키만)
    if (secure && typeof onKeyClick === "function") {
      const ghostIdxs = _numkeypadPickGhostIndices(idx, keys.length);
      for (let i = 0; i < ghostIdxs.length; i += 1) {
        const gValue = keys[ghostIdxs[i]];
        try {
          onKeyClick(gValue, { ghost: true });
        } catch (e) {
          if (window.console && console.error) {
            console.error("[NumberKeypad] ghost onKeyClick threw:", e);
          }
        }
      }
    }
  };

  /* 격자 렌더: 12셀. 순서는 [0..8 숫자1~9, 빈칸, 숫자10(0), Backspace] */
  const cells = [];
  // 1~9 (keys[0..8])
  for (let i = 0; i < 9; i += 1) {
    const v = String(keys[i]);
    cells.push(
      <button
        key={"num-" + i + "-" + v}
        type="button"
        className="tds-numkeypad__cell tds-numkeypad__cell--number"
        aria-label={v}
        disabled={disabled}
        onClick={() => handlePress(i)}
      >
        <span className="tds-numkeypad__label">{v}</span>
      </button>
    );
  }
  // 빈 셀 (row=3, col=0)
  cells.push(
    <div
      key="pad-empty"
      className="tds-numkeypad__cell tds-numkeypad__cell--empty"
      aria-hidden="true"
    />
  );
  // 10번째 숫자 (keys[9], 기본 0) — row=3, col=1
  {
    const v = String(keys[9]);
    cells.push(
      <button
        key={"num-9-" + v}
        type="button"
        className="tds-numkeypad__cell tds-numkeypad__cell--number"
        aria-label={v}
        disabled={disabled}
        onClick={() => handlePress(9)}
      >
        <span className="tds-numkeypad__label">{v}</span>
      </button>
    );
  }
  // Backspace — row=3, col=2
  cells.push(
    <button
      key="bksp"
      type="button"
      className="tds-numkeypad__cell tds-numkeypad__cell--backspace"
      aria-label={backspaceAriaLabel}
      disabled={disabled}
      onClick={() => {
        if (disabled) return;
        if (typeof onBackspaceClick === "function") onBackspaceClick();
      }}
    >
      <span className="tds-numkeypad__icon">
        <_NumberKeypadBackspaceIcon />
      </span>
    </button>
  );

  const rootCls =
    "tds-numkeypad" +
    (disabled ? " tds-numkeypad--disabled" : "") +
    (secure ? " tds-numkeypad--secure" : "") +
    (className ? " " + className : "");

  return (
    <div
      className={rootCls}
      style={style}
      role="group"
      aria-label={secure ? "보안 숫자 키패드" : "숫자 키패드"}
      data-secure={secure ? "true" : "false"}
      {...rest}
    >
      {cells}
    </div>
  );
}

// 글로벌 등록
window.NumberKeypad = NumberKeypad;
