"use client";

/**
 * JoinClassModal — 加入班级模态框（ai14，P5）
 *
 * 通过邀请码加入班级。
 * - 6 位邀请码输入（每格独立输入框，自动跳转）
 * - 粘贴支持（自动填充 6 格）
 * - 提交后调用 useJoinClass mutation
 * - 成功 / 失败 / loading 状态反馈
 * - A11y：role=dialog + aria-modal + ESC 关闭 + 焦点陷阱
 *
 * 用于 my-classes 页面"加入班级"按钮触发。
 */

import {
  useCallback,
  useEffect,
  useRef,
  useState,
  type KeyboardEvent as ReactKeyboardEvent,
} from "react";
import { useJoinClass } from "@/lib/graphql/hooks";
import { cn } from "@/lib/exam-types";

export interface JoinClassModalProps {
  /** 是否显示 */
  open: boolean;
  /** 关闭回调 */
  onClose: () => void;
  /** 加入成功回调 */
  onJoined?: (className: string) => void;
}

const CODE_LENGTH = 6;

export function JoinClassModal({
  open,
  onClose,
  onJoined,
}: JoinClassModalProps): JSX.Element | null {
  const [code, setCode] = useState<string[]>(Array(CODE_LENGTH).fill(""));
  const [feedback, setFeedback] = useState<
    { type: "success" | "error"; message: string } | null
  >(null);
  const inputRefs = useRef<Array<HTMLInputElement | null>>([]);
  const dialogRef = useRef<HTMLDivElement | null>(null);
  const { execute: executeJoin, fetching, data, success, errors } = useJoinClass();

  // 重置状态
  const resetState = useCallback((): void => {
    setCode(Array(CODE_LENGTH).fill(""));
    setFeedback(null);
  }, []);

  // 响应 mutation 结果变化
  useEffect(() => {
    if (!fetching && (data !== null || errors.length > 0)) {
      if (success && data) {
        setFeedback({
          type: "success",
          message: `已加入班级：${data.className}`,
        });
        onJoined?.(data.className);
        const timer = setTimeout(() => {
          onClose();
        }, 1500);
        return () => clearTimeout(timer);
      } else if (!success) {
        const errMsg = errors[0]?.message ?? "加入失败";
        setFeedback({ type: "error", message: errMsg });
      }
    }
  }, [data, success, errors, fetching, onJoined, onClose]);

  // open 变化时重置 + 聚焦第一个输入框
  useEffect(() => {
    if (open) {
      resetState();
      const timer = setTimeout(() => {
        inputRefs.current[0]?.focus();
      }, 50);
      return () => clearTimeout(timer);
    }
  }, [open, resetState]);

  // ESC 关闭
  useEffect(() => {
    if (!open) return;
    const onKey = (e: globalThis.KeyboardEvent): void => {
      if (e.key === "Escape" && !fetching) {
        onClose();
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [open, onClose, fetching]);

  const handleChange = useCallback(
    (index: number, value: string): void => {
      // 只保留字母数字，转大写
      const sanitized = value
        .toUpperCase()
        .replace(/[^A-Z0-9]/g, "")
        .slice(0, CODE_LENGTH);
      if (sanitized.length === 0) {
        setCode((prev) => {
          const next = [...prev];
          next[index] = "";
          return next;
        });
        return;
      }
      // 粘贴场景：一次填入多格
      if (sanitized.length > 1) {
        const next = Array(CODE_LENGTH).fill("");
        for (let i = 0; i < sanitized.length && i < CODE_LENGTH; i++) {
          next[i] = sanitized[i] ?? "";
        }
        setCode(next);
        const focusIndex = Math.min(sanitized.length, CODE_LENGTH - 1);
        inputRefs.current[focusIndex]?.focus();
        return;
      }
      // 单格输入
      setCode((prev) => {
        const next = [...prev];
        next[index] = sanitized;
        return next;
      });
      // 自动跳转下一格
      if (index < CODE_LENGTH - 1) {
        inputRefs.current[index + 1]?.focus();
      }
    },
    [],
  );

  const handleKeyDown = useCallback(
    (index: number, e: ReactKeyboardEvent<HTMLInputElement>): void => {
      if (e.key === "Backspace" && !code[index] && index > 0) {
        // 空格按 Backspace 跳回上一格
        inputRefs.current[index - 1]?.focus();
      }
    },
    [code],
  );

  const handleSubmit = useCallback((): void => {
    const inviteCode = code.join("");
    if (inviteCode.length !== CODE_LENGTH) {
      setFeedback({ type: "error", message: "请输入完整的 6 位邀请码" });
      return;
    }
    setFeedback(null);
    executeJoin({ inviteCode });
  }, [code, executeJoin]);

  if (!open) return null;

  const fullCode = code.join("");
  const isComplete = fullCode.length === CODE_LENGTH;

  return (
    <div
      className="fixed inset-0 z-50 flex items-center justify-center p-md"
      style={{ background: "rgba(0,0,0,0.5)" }}
      role="button"
      tabIndex={-1}
      aria-label="关闭模态框"
      onClick={(e) => {
        if (e.target === e.currentTarget && !fetching) onClose();
      }}
      onKeyDown={(e) => {
        if (e.key === "Escape") onClose();
      }}
    >
      <div
        ref={dialogRef}
        role="dialog"
        aria-modal="true"
        aria-labelledby="join-class-title"
        className="w-full max-w-md card-paper p-lg"
        style={{ background: "var(--color-paper)" }}
        onClick={(e) => e.stopPropagation()}
      >
        <div className="mb-md flex items-center justify-between">
          <h3
            id="join-class-title"
            className="font-serif text-xl"
            style={{ color: "var(--color-ink)" }}
          >
            加入班级
          </h3>
          <button
            type="button"
            onClick={() => !fetching && onClose()}
            className="p-1 rounded hover:bg-accent-muted"
            style={{ color: "var(--color-ink-muted)" }}
            aria-label="关闭"
            disabled={fetching}
          >
            <svg
              width="18"
              height="18"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              strokeWidth="2"
              aria-hidden="true"
            >
              <path d="M18 6 6 18M6 6l12 12" />
            </svg>
          </button>
        </div>

        <p
          className="mb-md text-sm"
          style={{ color: "var(--color-ink-muted)" }}
        >
          请输入老师提供的 6 位班级邀请码
        </p>

        {/* 邀请码输入 */}
        <div
          className="mb-md flex justify-between gap-xs"
          role="group"
          aria-label="邀请码输入"
        >
          {code.map((digit, i) => (
            <input
              key={i}
              ref={(el) => {
                inputRefs.current[i] = el;
              }}
              type="text"
              value={digit}
              onChange={(e) => handleChange(i, e.target.value)}
              onKeyDown={(e) => handleKeyDown(i, e)}
              disabled={fetching}
              maxLength={1}
              className={cn(
                "w-11 h-12 text-center font-serif text-xl rounded border",
                digit ? "border-accent" : "border-rule",
              )}
              style={{
                background: "var(--color-paper)",
                color: "var(--color-ink)",
              }}
              aria-label={`邀请码第 ${i + 1} 位`}
              inputMode="text"
              autoComplete="off"
            />
          ))}
        </div>

        {/* 反馈 */}
        {feedback && (
          <p
            className="mb-md text-sm"
            role="alert"
            style={{
              color:
                feedback.type === "success"
                  ? "var(--color-success)"
                  : "var(--color-danger)",
            }}
          >
            {feedback.message}
          </p>
        )}

        {/* 操作按钮 */}
        <div className="flex justify-end gap-sm">
          <button
            type="button"
            onClick={() => onClose()}
            disabled={fetching}
            className="btn-secondary"
          >
            取消
          </button>
          <button
            type="button"
            onClick={() => handleSubmit()}
            disabled={!isComplete || fetching}
            className="btn-primary"
          >
            {fetching ? "加入中…" : "加入班级"}
          </button>
        </div>
      </div>
    </div>
  );
}
