/**
 * useSubmitDedup Hook 测试
 *
 * 测试提交去重逻辑：
 * - markSubmitting 生成唯一幂等 key
 * - markComplete 后可以再次 markSubmitting
 * - lockRef 防止重复点击
 */

import { describe, it, expect, beforeEach, vi } from "vitest";
import { renderHook, act } from "@testing-library/react";
import { useSubmitDedup } from "./use-submit-dedup";

describe("useSubmitDedup", () => {
  const examId = "exam-001";

  beforeEach(() => {
    vi.restoreAllMocks();
  });

  it("初始状态 isSubmitting 应为 false", () => {
    const { result } = renderHook(() => useSubmitDedup(examId));
    expect(result.current.isSubmitting).toBe(false);
  });

  it("初始状态 canSubmit 应为 true", () => {
    const { result } = renderHook(() => useSubmitDedup(examId));
    expect(result.current.canSubmit).toBe(true);
  });

  it("初始应生成 idempotencyKey", () => {
    const { result } = renderHook(() => useSubmitDedup(examId));
    expect(result.current.idempotencyKey).toBeTruthy();
    expect(typeof result.current.idempotencyKey).toBe("string");
  });

  it("idempotencyKey 应包含 examId", () => {
    const { result } = renderHook(() => useSubmitDedup(examId));
    expect(result.current.idempotencyKey).toContain(`exam-${examId}`);
  });

  describe("markSubmitting", () => {
    it("markSubmitting 后 isSubmitting 应为 true", () => {
      const { result } = renderHook(() => useSubmitDedup(examId));
      act(() => {
        result.current.markSubmitting();
      });
      expect(result.current.isSubmitting).toBe(true);
    });

    it("markSubmitting 后 canSubmit 应为 false", () => {
      const { result } = renderHook(() => useSubmitDedup(examId));
      act(() => {
        result.current.markSubmitting();
      });
      expect(result.current.canSubmit).toBe(false);
    });

    it("markSubmitting 后应生成新的 idempotencyKey", () => {
      const { result } = renderHook(() => useSubmitDedup(examId));
      const initialKey = result.current.idempotencyKey;
      act(() => {
        result.current.markSubmitting();
      });
      expect(result.current.idempotencyKey).not.toBe(initialKey);
    });

    it("重复调用 markSubmitting 不应改变状态（lockRef 保护）", () => {
      const { result } = renderHook(() => useSubmitDedup(examId));
      act(() => {
        result.current.markSubmitting();
      });
      const keyAfterFirst = result.current.idempotencyKey;

      act(() => {
        result.current.markSubmitting();
      });
      // key 不应变（lockRef 阻止了第二次）
      expect(result.current.idempotencyKey).toBe(keyAfterFirst);
      expect(result.current.isSubmitting).toBe(true);
    });
  });

  describe("markComplete", () => {
    it("markComplete 后 isSubmitting 应为 false", () => {
      const { result } = renderHook(() => useSubmitDedup(examId));
      act(() => {
        result.current.markSubmitting();
        result.current.markComplete();
      });
      expect(result.current.isSubmitting).toBe(false);
    });

    it("markComplete 后 canSubmit 应为 true", () => {
      const { result } = renderHook(() => useSubmitDedup(examId));
      act(() => {
        result.current.markSubmitting();
        result.current.markComplete();
      });
      expect(result.current.canSubmit).toBe(true);
    });

    it("markComplete 后应生成新的 idempotencyKey", () => {
      const { result } = renderHook(() => useSubmitDedup(examId));
      act(() => {
        result.current.markSubmitting();
      });
      const keyAfterSubmit = result.current.idempotencyKey;

      act(() => {
        result.current.markComplete();
      });
      expect(result.current.idempotencyKey).not.toBe(keyAfterSubmit);
    });

    it("markComplete 后可以再次 markSubmitting", () => {
      const { result } = renderHook(() => useSubmitDedup(examId));
      // 第一次提交
      act(() => {
        result.current.markSubmitting();
      });
      expect(result.current.isSubmitting).toBe(true);

      // 完成
      act(() => {
        result.current.markComplete();
      });
      expect(result.current.isSubmitting).toBe(false);
      expect(result.current.canSubmit).toBe(true);

      // 第二次提交
      act(() => {
        result.current.markSubmitting();
      });
      expect(result.current.isSubmitting).toBe(true);
      expect(result.current.canSubmit).toBe(false);
    });
  });

  describe("幂等 key 唯一性", () => {
    it("不同 Hook 实例应生成不同的初始 key", () => {
      const { result: r1 } = renderHook(() => useSubmitDedup(examId));
      const { result: r2 } = renderHook(() => useSubmitDedup(examId));
      expect(r1.current.idempotencyKey).not.toBe(r2.current.idempotencyKey);
    });

    it("完整提交周期应生成 3 个不同的 key（初始 → submitting → complete）", () => {
      const { result } = renderHook(() => useSubmitDedup(examId));
      const keys: string[] = [result.current.idempotencyKey];

      act(() => {
        result.current.markSubmitting();
      });
      keys.push(result.current.idempotencyKey);

      act(() => {
        result.current.markComplete();
      });
      keys.push(result.current.idempotencyKey);

      // 三个 key 应互不相同
      expect(new Set(keys).size).toBe(3);
    });

    it("多次提交周期每次都应生成不同的 key", () => {
      const { result } = renderHook(() => useSubmitDedup(examId));
      const keys: string[] = [];

      for (let i = 0; i < 3; i++) {
        act(() => {
          result.current.markSubmitting();
        });
        keys.push(result.current.idempotencyKey);
        act(() => {
          result.current.markComplete();
        });
      }

      // 每次提交的 key 应唯一
      expect(new Set(keys).size).toBe(keys.length);
    });
  });

  describe("重复点击防护", () => {
    it("快速连续点击 markSubmitting 只应生效一次", () => {
      const { result } = renderHook(() => useSubmitDedup(examId));

      act(() => {
        result.current.markSubmitting();
        result.current.markSubmitting();
        result.current.markSubmitting();
      });

      expect(result.current.isSubmitting).toBe(true);
      // canSubmit 仍为 false（已被锁定）
      expect(result.current.canSubmit).toBe(false);
    });

    it("markComplete 后 lockRef 解锁，可以再次提交", () => {
      const { result } = renderHook(() => useSubmitDedup(examId));

      // 第一次提交周期
      act(() => {
        result.current.markSubmitting();
        result.current.markSubmitting(); // 重复点击
      });
      expect(result.current.canSubmit).toBe(false);

      act(() => {
        result.current.markComplete();
      });
      expect(result.current.canSubmit).toBe(true);

      // 第二次提交周期
      act(() => {
        result.current.markSubmitting();
      });
      expect(result.current.isSubmitting).toBe(true);
      expect(result.current.canSubmit).toBe(false);
    });
  });

  describe("examId 变化", () => {
    it("examId 变化后 markSubmitting 应使用新 examId 生成 key", () => {
      const { result, rerender } = renderHook(
        ({ id }) => useSubmitDedup(id),
        { initialProps: { id: "exam-001" } },
      );

      rerender({ id: "exam-002" });

      act(() => {
        result.current.markSubmitting();
      });

      expect(result.current.idempotencyKey).toContain("exam-exam-002");
    });
  });
});
