/**
 * 滑块验证码 UI（登录/注册共用）
 * 画布固定 280×120，与 API SVG 坐标一致。
 */
const BiliIndexCaptcha = (globalThis.BiliIndexCaptcha = globalThis.BiliIndexCaptcha || {});

BiliIndexCaptcha._state = {
  captchaId: "",
  trackWidth: 280,
  canvasHeight: 120,
  puzzleWidth: 44,
  puzzleY: 40,
  slideX: 0,
  verified: false,
  dragging: false,
  dragStartX: 0,
  dragStartSlide: 0,
  checking: false,
};

BiliIndexCaptcha._refreshing = false;

BiliIndexCaptcha.mount = (wrapEl) => {
  if (!wrapEl) return;
  wrapEl.innerHTML = `
    <div class="captcha-slider" role="group" aria-label="滑块验证">
      <div class="captcha-slider-visual">
        <div class="captcha-slider-piece" aria-hidden="true"></div>
      </div>
      <div class="captcha-slider-track">
        <div class="captcha-slider-fill"></div>
        <div class="captcha-slider-knob" tabindex="0" role="slider" aria-label="拖动滑块"></div>
      </div>
      <div class="captcha-slider-hint">请拖动滑块，使上方色块与缺口重合</div>
      <button type="button" class="captcha-slider-refresh link-btn">刷新验证码</button>
    </div>
  `;
  BiliIndexCaptcha._wrap = wrapEl;
  BiliIndexCaptcha._els = {
    visual: wrapEl.querySelector(".captcha-slider-visual"),
    track: wrapEl.querySelector(".captcha-slider-track"),
    piece: wrapEl.querySelector(".captcha-slider-piece"),
    fill: wrapEl.querySelector(".captcha-slider-fill"),
    knob: wrapEl.querySelector(".captcha-slider-knob"),
    hint: wrapEl.querySelector(".captcha-slider-hint"),
    refresh: wrapEl.querySelector(".captcha-slider-refresh"),
  };
  BiliIndexCaptcha._els.refresh.addEventListener("click", () => BiliIndexCaptcha.refresh());
  BiliIndexCaptcha._bindDrag();
};

BiliIndexCaptcha._trackScale = () => {
  const track = BiliIndexCaptcha._els.track;
  const s = BiliIndexCaptcha._state;
  if (!track) return 1;
  const w = track.getBoundingClientRect().width;
  return w > 0 ? s.trackWidth / w : 1;
};

BiliIndexCaptcha._maxSlide = () => {
  const s = BiliIndexCaptcha._state;
  return Math.max(0, s.trackWidth - s.puzzleWidth);
};

BiliIndexCaptcha._applySlide = (x) => {
  const s = BiliIndexCaptcha._state;
  const max = BiliIndexCaptcha._maxSlide();
  s.slideX = Math.min(max, Math.max(0, Math.round(x)));
  s.verified = false;
  const { piece, fill, knob } = BiliIndexCaptcha._els;
  if (piece) {
    piece.style.transform = `translate3d(${s.slideX}px, ${s.puzzleY}px, 0)`;
  }
  if (fill) fill.style.width = `${s.slideX + s.puzzleWidth / 2}px`;
  if (knob) {
    knob.style.transform = `translate3d(${s.slideX}px, 0, 0)`;
    knob.setAttribute("aria-valuenow", String(s.slideX));
    knob.setAttribute("aria-valuemax", String(max));
  }
};

BiliIndexCaptcha._bindDrag = () => {
  const knob = BiliIndexCaptcha._els.knob;
  if (!knob) return;

  const onDown = (clientX) => {
    BiliIndexCaptcha._state.dragging = true;
    BiliIndexCaptcha._state.dragStartX = clientX;
    BiliIndexCaptcha._state.dragStartSlide = BiliIndexCaptcha._state.slideX;
    BiliIndexCaptcha._state.verified = false;
    BiliIndexCaptcha._setHint("拖动滑块使色块与缺口重合", false);
  };

  const onMove = (clientX) => {
    if (!BiliIndexCaptcha._state.dragging) return;
    const scale = BiliIndexCaptcha._trackScale();
    const dx = (clientX - BiliIndexCaptcha._state.dragStartX) * scale;
    BiliIndexCaptcha._applySlide(BiliIndexCaptcha._state.dragStartSlide + dx);
  };

  const onUp = async () => {
    const s = BiliIndexCaptcha._state;
    if (!s.dragging) return;
    s.dragging = false;
    if (s.slideX <= 4 || !s.captchaId) {
      s.verified = false;
      return;
    }
    if (s.checking) return;
    s.checking = true;
    BiliIndexCaptcha._setHint("校验对齐中…", false);
    try {
      const ok = await BiliIndex.checkSliderCaptcha(s.captchaId, s.slideX);
      s.verified = ok;
      if (ok) {
        BiliIndexCaptcha._setHint("验证通过，可点击登录/注册", false, true);
      } else {
        BiliIndexCaptcha._setHint("未对齐，请微调滑块或刷新验证码", true);
      }
    } catch (e) {
      s.verified = false;
      BiliIndexCaptcha._setHint(e.message || "校验失败，请刷新验证码", true);
    } finally {
      s.checking = false;
    }
  };

  knob.addEventListener("mousedown", (e) => {
    e.preventDefault();
    onDown(e.clientX);
  });
  window.addEventListener("mousemove", (e) => onMove(e.clientX));
  window.addEventListener("mouseup", () => {
    void onUp();
  });

  knob.addEventListener(
    "touchstart",
    (e) => {
      e.preventDefault();
      onDown(e.touches[0].clientX);
    },
    { passive: false }
  );
  window.addEventListener("touchmove", (e) => onMove(e.touches[0].clientX), { passive: true });
  window.addEventListener("touchend", () => {
    void onUp();
  });
};

BiliIndexCaptcha._setHint = (text, isError = false, ok = false) => {
  const el = BiliIndexCaptcha._els?.hint;
  if (!el) return;
  el.textContent = text;
  el.classList.toggle("error", isError);
  el.classList.toggle("ok", ok);
};

BiliIndexCaptcha._layoutCanvas = () => {
  const s = BiliIndexCaptcha._state;
  const { visual, track, piece } = BiliIndexCaptcha._els;
  if (visual) {
    visual.style.width = `${s.trackWidth}px`;
    visual.style.height = `${s.canvasHeight}px`;
    visual.style.backgroundSize = `${s.trackWidth}px ${s.canvasHeight}px`;
  }
  if (track) {
    track.style.width = `${s.trackWidth}px`;
  }
  if (piece) {
    piece.style.width = `${s.puzzleWidth}px`;
    piece.style.height = `${s.puzzleWidth}px`;
  }
};

BiliIndexCaptcha.refresh = async () => {
  if (BiliIndexCaptcha._refreshing) return;
  BiliIndexCaptcha._refreshing = true;
  BiliIndexCaptcha._state.verified = false;
  BiliIndexCaptcha._state.slideX = 0;
  BiliIndexCaptcha._setHint("加载验证码…", false);
  try {
    const data = await BiliIndex.fetchSliderCaptcha();
    const s = BiliIndexCaptcha._state;
    s.captchaId = data.captcha_id;
    s.trackWidth = data.track_width || 280;
    s.canvasHeight = data.canvas_height || 120;
    s.puzzleWidth = data.puzzle_width || 44;
    s.puzzleY = data.puzzle_y ?? 40;
    BiliIndexCaptcha._layoutCanvas();
    if (BiliIndexCaptcha._els.visual && data.bg_image) {
      BiliIndexCaptcha._els.visual.style.backgroundImage = `url("${data.bg_image}")`;
    }
    BiliIndexCaptcha._applySlide(0);
    BiliIndexCaptcha._setHint("请拖动滑块，使上方色块与缺口重合", false);
  } catch (e) {
    BiliIndexCaptcha._state.captchaId = "";
    const base = await BiliIndex.getApiBase?.().catch(() => "");
    const msg =
      typeof BiliIndex.humanizeApiError === "function"
        ? BiliIndex.humanizeApiError(e, base)
        : e.message || "验证码加载失败";
    BiliIndexCaptcha._setHint(msg, true);
  } finally {
    BiliIndexCaptcha._refreshing = false;
  }
};

BiliIndexCaptcha.getPayload = () => {
  const s = BiliIndexCaptcha._state;
  if (!s.captchaId || !s.verified) {
    throw new Error("请先拖动滑块并通过验证");
  }
  return { captcha_id: s.captchaId, captcha_x: s.slideX };
};

BiliIndexCaptcha.resetAfterSubmit = () => {
  void BiliIndexCaptcha.refresh();
};

BiliIndexCaptcha.isCaptchaError = (message) => {
  const m = String(message || "");
  return /滑块|验证码|captcha/i.test(m);
};

BiliIndexCaptcha._scrollIntoView = () => {
  const wrap = document.getElementById("auth-captcha-wrap");
  if (!wrap || wrap.classList.contains("hidden")) return;
  requestAnimationFrame(() => {
    try {
      wrap.scrollIntoView({ block: "nearest", behavior: "smooth" });
    } catch {
      wrap.scrollIntoView();
    }
  });
};

BiliIndexCaptcha.setVisible = (show) => {
  const wrap = document.getElementById("auth-captcha-wrap");
  if (!wrap) return;
  wrap.classList.toggle("hidden", !show);
  wrap.setAttribute("aria-hidden", show ? "false" : "true");
  if (show) {
    if (!BiliIndexCaptcha._els?.track) {
      const slot =
        document.getElementById("login-captcha-slot") ||
        document.getElementById("register-captcha-slot");
      if (slot && !slot.contains(wrap)) {
        slot.appendChild(wrap);
      }
      if (!BiliIndexCaptcha._els?.track) {
        BiliIndexCaptcha.mount(wrap);
      }
    }
    if (!BiliIndexCaptcha._state.captchaId && !BiliIndexCaptcha._refreshing) {
      void BiliIndexCaptcha.refresh().finally(() => BiliIndexCaptcha._scrollIntoView());
    } else {
      BiliIndexCaptcha._scrollIntoView();
    }
  }
};
