import { describe, it, expect, vi, beforeEach } from "vitest";
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import AuthModal from "./AuthModal";

vi.mock("@/lib/userId", () => ({
  setCachedProfile: vi.fn(),
}));

const mockFetch = vi.fn();
vi.stubGlobal("fetch", mockFetch);

const mockOnAuth = vi.fn();
const mockOnClose = vi.fn();

beforeEach(() => {
  vi.clearAllMocks();
  // Reset localStorage
  Object.defineProperty(window, "localStorage", {
    value: { setItem: vi.fn(), getItem: vi.fn(), removeItem: vi.fn() },
    writable: true,
  });
});

function renderModal(props = {}) {
  return render(
    <AuthModal open onClose={mockOnClose} onAuth={mockOnAuth} {...props} />,
  );
}

describe("AuthModal", () => {
  it("renders login tab by default", () => {
    renderModal();
    expect(screen.getAllByText("登录").length).toBeGreaterThanOrEqual(1);
    expect(screen.getAllByText("注册").length).toBeGreaterThanOrEqual(1);
    expect(screen.getByPlaceholderText("请输入用户名")).toBeInTheDocument();
  });

  it("renders register tab when specified", () => {
    renderModal({ defaultTab: "register" });
    expect(screen.getByPlaceholderText("2-16 个字符")).toBeInTheDocument();
    expect(screen.getByText("确认密码")).toBeInTheDocument();
  });

  it("switches between login and register tabs", async () => {
    renderModal();
    expect(screen.getByPlaceholderText("请输入用户名")).toBeInTheDocument();

    fireEvent.click(screen.getByText("注册"));
    expect(screen.getByPlaceholderText("2-16 个字符")).toBeInTheDocument();
    expect(screen.getByText("确认密码")).toBeInTheDocument();
  });

  it("shows error when username is empty", async () => {
    renderModal();
    const submitBtn = screen.getAllByText("登录").find(
      (el) => el.closest("button[class*='bg-accent']"),
    )!;
    fireEvent.click(submitBtn);
    await waitFor(() => {
      expect(screen.getByText("请输入用户名")).toBeInTheDocument();
    });
  });

  it("shows error when password is empty", async () => {
    renderModal();
    const user = userEvent.setup();
    await user.type(screen.getByPlaceholderText("请输入用户名"), "testuser");
    const submitBtn = screen.getAllByText("登录").find(
      (el) => el.closest("button[class*='bg-accent']"),
    )!;
    fireEvent.click(submitBtn);
    await waitFor(() => {
      expect(screen.getByText("请输入密码")).toBeInTheDocument();
    });
  });

  it("shows register-specific validation errors", async () => {
    renderModal({ defaultTab: "register" });
    const user = userEvent.setup();

    await user.type(screen.getByPlaceholderText("2-16 个字符"), "a");
    await user.type(screen.getByPlaceholderText("至少 6 个字符"), "123456");
    await user.type(screen.getByPlaceholderText("再次输入密码"), "654321");

    const submitBtn = screen.getAllByText("注册").find(
      (el) => el.closest("button[class*='bg-accent']"),
    )!;
    fireEvent.click(submitBtn);

    await waitFor(() => {
      expect(screen.getByText("用户名需要 2-16 个字符")).toBeInTheDocument();
    });
  });

  it("shows password mismatch error during registration", async () => {
    renderModal({ defaultTab: "register" });
    const user = userEvent.setup();

    await user.type(screen.getByPlaceholderText("2-16 个字符"), "testuser");
    await user.type(screen.getByPlaceholderText("至少 6 个字符"), "123456");
    await user.type(screen.getByPlaceholderText("再次输入密码"), "654321");

    const submitBtn = screen.getAllByText("注册").find(
      (el) => el.closest("button[class*='bg-accent']"),
    )!;
    fireEvent.click(submitBtn);

    await waitFor(() => {
      expect(screen.getByText("两次密码不一致")).toBeInTheDocument();
    });
  });

  it("submits login successfully", async () => {
    mockFetch.mockResolvedValue({
      ok: true,
      json: () => Promise.resolve({ id: "u1", username: "testuser", avatar: "🐱" }),
    });

    renderModal();
    const user = userEvent.setup();

    await user.type(screen.getByPlaceholderText("请输入用户名"), "testuser");
    await user.type(screen.getByPlaceholderText("请输入密码"), "password123");

    const submitBtn = screen.getAllByText("登录").find(
      (el) => el.closest("button[class*='bg-accent']"),
    )!;
    fireEvent.click(submitBtn);

    await waitFor(() => {
      expect(mockOnAuth).toHaveBeenCalledWith({
        id: "u1",
        username: "testuser",
        avatar: "🐱",
      });
      expect(mockOnClose).toHaveBeenCalled();
    });
  });

  it("shows API error on failed login", async () => {
    mockFetch.mockResolvedValue({
      ok: false,
      json: () => Promise.resolve({ error: "用户名或密码错误" }),
    });

    renderModal();
    const user = userEvent.setup();

    await user.type(screen.getByPlaceholderText("请输入用户名"), "testuser");
    await user.type(screen.getByPlaceholderText("请输入密码"), "wrong");

    const submitBtn = screen.getAllByText("登录").find(
      (el) => el.closest("button[class*='bg-accent']"),
    )!;
    fireEvent.click(submitBtn);

    await waitFor(() => {
      expect(screen.getByText("用户名或密码错误")).toBeInTheDocument();
    });
  });

  it("shows network error on fetch failure", async () => {
    mockFetch.mockRejectedValue(new Error("network"));

    renderModal();
    const user = userEvent.setup();

    await user.type(screen.getByPlaceholderText("请输入用户名"), "testuser");
    await user.type(screen.getByPlaceholderText("请输入密码"), "password123");

    const submitBtn = screen.getAllByText("登录").find(
      (el) => el.closest("button[class*='bg-accent']"),
    )!;
    fireEvent.click(submitBtn);

    await waitFor(() => {
      expect(screen.getByText("网络错误，请重试")).toBeInTheDocument();
    });
  });

  it("toggles password visibility", () => {
    renderModal();
    const toggle = screen.getByLabelText("显示密码");
    const passwordInput = screen.getByPlaceholderText("请输入密码");

    expect(passwordInput).toHaveAttribute("type", "password");
    fireEvent.click(toggle);
    expect(passwordInput).toHaveAttribute("type", "text");
  });

  it("does not render when closed", () => {
    render(
      <AuthModal open={false} onClose={mockOnClose} onAuth={mockOnAuth} />,
    );
    expect(screen.queryByText("欢迎")).not.toBeInTheDocument();
  });

  it("renders avatar selection in register mode", () => {
    renderModal({ defaultTab: "register" });
    expect(screen.getByText("选择头像")).toBeInTheDocument();
    expect(screen.getByText("🐱")).toBeInTheDocument();
  });
});
