// LeaveRequestList 组件单测
// 依据：02-architecture-design.md §15 组件设计
// 覆盖：空态 / 全部列表渲染 / 状态筛选（all/pending/approved/rejected）/ 类型标签 / 状态标签 / 审批评论

import { describe, it, expect } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { LeaveRequestList } from "./LeaveRequestList";
import type { LeaveRequest } from "@/types";

const mockLeaveRequests: LeaveRequest[] = [
  {
    id: "leave-001",
    childId: "student-001",
    childName: "张小明",
    className: "初一(1)班",
    type: "sick",
    startDate: "2026-05-10",
    endDate: "2026-05-11",
    reason: "感冒发烧需要在家休息观察",
    status: "approved",
    submittedAt: "2026-05-09T20:15:00Z",
    reviewedAt: "2026-05-10T08:30:00Z",
    reviewerName: "王老师",
    reviewComment: "已批准，注意休息，按时复课",
  },
  {
    id: "leave-002",
    childId: "student-001",
    childName: "张小明",
    className: "初一(1)班",
    type: "personal",
    startDate: "2026-06-15",
    endDate: "2026-06-15",
    reason: "家中临时事务需要陪同办理",
    status: "pending",
    submittedAt: "2026-06-13T21:00:00Z",
  },
  {
    id: "leave-003",
    childId: "student-002",
    childName: "张小红",
    className: "五年级(2)班",
    type: "family",
    startDate: "2026-04-20",
    endDate: "2026-04-22",
    reason: "回老家参加亲属婚礼",
    status: "approved",
    submittedAt: "2026-04-15T19:30:00Z",
    reviewedAt: "2026-04-16T09:00:00Z",
    reviewerName: "李老师",
    reviewComment: "已批准，请提前补做作业",
  },
  {
    id: "leave-004",
    childId: "student-001",
    childName: "张小明",
    className: "初一(1)班",
    type: "other",
    startDate: "2026-03-01",
    endDate: "2026-03-02",
    reason: "其他原因请假说明文字",
    status: "rejected",
    submittedAt: "2026-02-28T10:00:00Z",
    reviewedAt: "2026-03-01T08:00:00Z",
    reviewerName: "王老师",
    reviewComment: "请假理由不充分，请补充材料",
  },
];

describe("LeaveRequestList 空态", () => {
  it("空数组渲染暂无请假记录", () => {
    render(<LeaveRequestList leaveRequests={[]} />);
    expect(screen.getByText("暂无请假记录")).toBeInTheDocument();
  });
});

describe("LeaveRequestList 渲染", () => {
  it("渲染筛选 tab（全部/待审批/已批准/已驳回）", () => {
    render(<LeaveRequestList leaveRequests={mockLeaveRequests} />);
    expect(screen.getByRole("tablist", { name: "请假状态筛选" })).toBeInTheDocument();
    expect(screen.getByRole("tab", { name: "全部" })).toBeInTheDocument();
    expect(screen.getByRole("tab", { name: "待审批" })).toBeInTheDocument();
    expect(screen.getByRole("tab", { name: "已批准" })).toBeInTheDocument();
    expect(screen.getByRole("tab", { name: "已驳回" })).toBeInTheDocument();
  });

  it("默认全部 tab 选中", () => {
    render(<LeaveRequestList leaveRequests={mockLeaveRequests} />);
    const allTab = screen.getByRole("tab", { name: "全部" });
    expect(allTab).toHaveAttribute("aria-selected", "true");
  });

  it("默认显示全部 4 条记录", () => {
    const { container } = render(<LeaveRequestList leaveRequests={mockLeaveRequests} />);
    // 每条记录的类型标签渲染在 h3 中，计数 h3 验证记录数
    const typeHeadings = container.querySelectorAll("h3");
    expect(typeHeadings).toHaveLength(4);
  });

  it("渲染每条记录的日期信息", () => {
    render(<LeaveRequestList leaveRequests={mockLeaveRequests} />);
    // 4 条记录，每条有起始/结束/提交日期
    expect(screen.getAllByText(/起始：/)).toHaveLength(4);
    expect(screen.getAllByText(/结束：/)).toHaveLength(4);
    expect(screen.getAllByText(/提交于：/)).toHaveLength(4);
  });

  it("渲染每条记录的请假原因", () => {
    render(<LeaveRequestList leaveRequests={mockLeaveRequests} />);
    expect(screen.getByText("感冒发烧需要在家休息观察")).toBeInTheDocument();
    expect(screen.getByText("家中临时事务需要陪同办理")).toBeInTheDocument();
    expect(screen.getByText("回老家参加亲属婚礼")).toBeInTheDocument();
    expect(screen.getByText("其他原因请假说明文字")).toBeInTheDocument();
  });

  it("渲染审批评论（当存在时）", () => {
    render(<LeaveRequestList leaveRequests={mockLeaveRequests} />);
    expect(screen.getByText("已批准，注意休息，按时复课")).toBeInTheDocument();
    expect(screen.getByText("已批准，请提前补做作业")).toBeInTheDocument();
    expect(screen.getByText("请假理由不充分，请补充材料")).toBeInTheDocument();
  });

  it("不渲染审批评论区块（当不存在时）", () => {
    const pendingOnly: LeaveRequest[] = [mockLeaveRequests[1]!];
    render(<LeaveRequestList leaveRequests={pendingOnly} />);
    expect(screen.queryByText(/审批人/)).not.toBeInTheDocument();
  });

  it("渲染状态标签（待审批/已批准/已驳回）", () => {
    render(<LeaveRequestList leaveRequests={mockLeaveRequests} />);
    // "待审批" 同时出现在筛选 tab 和状态标签中，共 2 处（1 tab + 1 status）
    const pendingAll = screen.getAllByText("待审批");
    expect(pendingAll).toHaveLength(2);
    // "已批准" 同时出现在筛选 tab 和状态标签中，共 3 处（1 tab + 2 status）
    const approvedAll = screen.getAllByText("已批准");
    expect(approvedAll).toHaveLength(3);
    // "已驳回" 同时出现在筛选 tab 和状态标签中，共 2 处（1 tab + 1 status）
    const rejectedAll = screen.getAllByText("已驳回");
    expect(rejectedAll).toHaveLength(2);
  });

  it("渲染审批人姓名（当存在时）", () => {
    render(<LeaveRequestList leaveRequests={mockLeaveRequests} />);
    // 3 条记录有审批人：王老师（2 次）+ 李老师（1 次）
    expect(screen.getAllByText(/王老师/)).toHaveLength(2);
    expect(screen.getAllByText(/李老师/)).toHaveLength(1);
  });
});

describe("LeaveRequestList 状态筛选", () => {
  it("点击待审批 tab 仅显示 pending 记录", async () => {
    const user = userEvent.setup();
    render(<LeaveRequestList leaveRequests={mockLeaveRequests} />);
    await user.click(screen.getByRole("tab", { name: "待审批" }));

    expect(screen.getByRole("tab", { name: "待审批" })).toHaveAttribute("aria-selected", "true");
    expect(screen.getByRole("tab", { name: "全部" })).toHaveAttribute("aria-selected", "false");
    // 仅 1 条 pending 记录（事假）
    expect(screen.getByText("事假")).toBeInTheDocument();
    expect(screen.queryByText("病假")).not.toBeInTheDocument();
    expect(screen.queryByText("家庭假")).not.toBeInTheDocument();
    expect(screen.queryByText("其他")).not.toBeInTheDocument();
  });

  it("点击已批准 tab 仅显示 approved 记录", async () => {
    const user = userEvent.setup();
    render(<LeaveRequestList leaveRequests={mockLeaveRequests} />);
    await user.click(screen.getByRole("tab", { name: "已批准" }));

    // 2 条 approved 记录（病假 + 家庭假）
    expect(screen.getByText("病假")).toBeInTheDocument();
    expect(screen.getByText("家庭假")).toBeInTheDocument();
    expect(screen.queryByText("事假")).not.toBeInTheDocument();
    expect(screen.queryByText("其他")).not.toBeInTheDocument();
  });

  it("点击已驳回 tab 仅显示 rejected 记录", async () => {
    const user = userEvent.setup();
    render(<LeaveRequestList leaveRequests={mockLeaveRequests} />);
    await user.click(screen.getByRole("tab", { name: "已驳回" }));

    // 1 条 rejected 记录（其他）
    expect(screen.getByText("其他")).toBeInTheDocument();
    expect(screen.queryByText("病假")).not.toBeInTheDocument();
    expect(screen.queryByText("事假")).not.toBeInTheDocument();
  });

  it("已驳回筛选无匹配记录时显示暂无请假记录", async () => {
    const user = userEvent.setup();
    const noRejected = mockLeaveRequests.filter((l) => l.status !== "rejected");
    render(<LeaveRequestList leaveRequests={noRejected} />);
    await user.click(screen.getByRole("tab", { name: "已驳回" }));
    expect(screen.getByText("暂无请假记录")).toBeInTheDocument();
  });

  it("点击全部 tab 恢复显示全部记录", async () => {
    const user = userEvent.setup();
    render(<LeaveRequestList leaveRequests={mockLeaveRequests} />);
    // 先切到待审批
    await user.click(screen.getByRole("tab", { name: "待审批" }));
    expect(screen.queryByText("病假")).not.toBeInTheDocument();
    // 再切回全部
    await user.click(screen.getByRole("tab", { name: "全部" }));
    expect(screen.getByText("病假")).toBeInTheDocument();
    expect(screen.getByText("事假")).toBeInTheDocument();
  });
});
