// 登录页集成测试（MSW + Next.js 路由）
// 依据：02-architecture-design.md §13 测试策略、ISSUE-004 登录走 REST
// 覆盖：正确凭据登录跳转 / 错误凭据显示错误 / 加载态

import {
  describe,
  it,
  expect,
  beforeAll,
  afterAll,
  afterEach,
  vi,
} from "vitest";
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { http, HttpResponse, delay } from "msw";
import LoginPage from "./page";
import { server } from "@/test/mocks/server";
import { mockLoginResponse } from "@/test/mocks/fixtures";

// mock next/navigation
const mockPush = vi.fn();
vi.mock("next/navigation", () => ({
  useRouter: () => ({ push: mockPush, replace: vi.fn(), refresh: vi.fn() }),
}));

beforeAll(() => server.listen({ onUnhandledRequest: "error" }));
afterEach(() => {
  server.resetHandlers();
  localStorage.clear();
  mockPush.mockReset();
});
afterAll(() => server.close());

describe("LoginPage 集成测试", () => {
  it("渲染登录表单", () => {
    render(<LoginPage />);
    expect(
      screen.getByRole("heading", { name: "Edu 家长端" }),
    ).toBeInTheDocument();
    expect(screen.getByLabelText("邮箱")).toBeInTheDocument();
    expect(screen.getByLabelText("密码")).toBeInTheDocument();
    expect(screen.getByRole("button", { name: "登录" })).toBeInTheDocument();
  });

  it("默认填充 mock 账号", () => {
    render(<LoginPage />);
    expect(screen.getByLabelText("邮箱")).toHaveValue("parent@example.com");
    expect(screen.getByLabelText("密码")).toHaveValue("password");
  });

  it("正确凭据登录后跳转到 dashboard", async () => {
    const user = userEvent.setup();
    render(<LoginPage />);
    await user.click(screen.getByRole("button", { name: "登录" }));

    await waitFor(() => {
      expect(mockPush).toHaveBeenCalledWith("/parent/dashboard");
    });
    // token 已写入 localStorage
    expect(localStorage.getItem("parent_access_token")).toBeTruthy();
  });

  it("错误凭据显示错误信息", async () => {
    const user = userEvent.setup();
    render(<LoginPage />);
    await user.clear(screen.getByLabelText("邮箱"));
    await user.type(screen.getByLabelText("邮箱"), "wrong@example.com");
    await user.clear(screen.getByLabelText("密码"));
    await user.type(screen.getByLabelText("密码"), "wrong");
    await user.click(screen.getByRole("button", { name: "登录" }));

    await waitFor(() => {
      expect(screen.getByRole("alert")).toHaveTextContent(/邮箱或密码错误/);
    });
    expect(mockPush).not.toHaveBeenCalled();
  });

  it("登录中显示加载态", async () => {
    // 使用延迟响应以观察加载态
    server.use(
      http.post("/api/v1/iam/login", async () => {
        await delay(200);
        return HttpResponse.json({ success: true, data: mockLoginResponse });
      }),
    );
    const user = userEvent.setup();
    render(<LoginPage />);
    await user.click(screen.getByRole("button", { name: "登录" }));
    // 按钮文本变为"登录中..."
    expect(screen.getByRole("button")).toHaveTextContent(/登录中/);
  });
});
