// ReportCardView 组件单测
// 依据：02-architecture-design.md §15 组件设计
// 覆盖：头部信息 / 各科成绩表 / 总分与排名 / 教师评语 / 校长评语（可选）/ 打印按钮

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

const mockReportCard: ReportCard = {
  childId: "student-001",
  childName: "张小明",
  className: "初一(1)班",
  academicYearId: "ay-2025-2026",
  academicYearName: "2025-2026",
  semester: 2,
  subjects: [
    {
      subject: "语文",
      score: 85,
      maxScore: 100,
      gradeLevel: "B",
      classAverage: 75,
      rank: 8,
      classSize: 45,
      teacherComment: "阅读理解能力较强，作文需加强立意深度",
    },
    {
      subject: "数学",
      score: 92,
      maxScore: 100,
      gradeLevel: "A",
      classAverage: 78,
      rank: 3,
      classSize: 45,
      teacherComment: "逻辑思维清晰，解题规范，继续保持",
    },
    {
      subject: "英语",
      score: 88,
      maxScore: 100,
      gradeLevel: "B",
      classAverage: 72,
      rank: 5,
      classSize: 45,
      teacherComment: "听力有进步，建议加强口语练习",
    },
    {
      subject: "物理",
      score: 95,
      maxScore: 100,
      gradeLevel: "A",
      classAverage: 80,
      rank: 2,
      classSize: 45,
      teacherComment: "实验探究能力突出，分析问题思路严谨",
    },
  ],
  overallScore: 90,
  classRank: 5,
  classSize: 45,
  teacherComment: "本学期学习态度认真，成绩稳中有进，望继续保持，加强薄弱环节",
  headTeacherComment: "该生品学兼优，关心集体，乐于助人，下学期可担任班干部锻炼能力",
  issuedAt: "2026-07-05T10:00:00Z",
};

describe("ReportCardView 头部信息", () => {
  it("渲染成绩报告单标题", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    expect(screen.getByText("成绩报告单")).toBeInTheDocument();
  });

  it("渲染学年与学期", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    expect(screen.getByText(/2025-2026 学年/)).toBeInTheDocument();
    expect(screen.getByText(/第 2 学期/)).toBeInTheDocument();
  });

  it("渲染学生姓名", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    expect(screen.getByText("张小明")).toBeInTheDocument();
  });

  it("渲染班级", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    expect(screen.getByText("初一(1)班")).toBeInTheDocument();
  });

  it("渲染签发日期", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    expect(screen.getByText(/签发日期/)).toBeInTheDocument();
  });
});

describe("ReportCardView 各科成绩表", () => {
  it("渲染各科成绩 section", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    expect(screen.getByLabelText("各科成绩")).toBeInTheDocument();
  });

  it("渲染成绩明细表（aria-label）", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    expect(screen.getByLabelText("各科成绩明细表")).toBeInTheDocument();
  });

  it("渲染表头（科目/分数/满分/等级/班均/班级排名）", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    expect(screen.getByText("科目")).toBeInTheDocument();
    expect(screen.getByText("分数")).toBeInTheDocument();
    expect(screen.getByText("满分")).toBeInTheDocument();
    expect(screen.getByText("等级")).toBeInTheDocument();
    expect(screen.getByText("班均")).toBeInTheDocument();
    // "班级排名" 同时出现在表头 th 和总分排名 section，用 getAllByText
    expect(screen.getAllByText("班级排名")).toHaveLength(2);
  });

  it("渲染 4 个学科行", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    expect(screen.getByText("语文")).toBeInTheDocument();
    expect(screen.getByText("数学")).toBeInTheDocument();
    expect(screen.getByText("英语")).toBeInTheDocument();
    expect(screen.getByText("物理")).toBeInTheDocument();
  });

  it("渲染每科分数与等级", () => {
    const { container } = render(<ReportCardView reportCard={mockReportCard} />);
    // 通过表格单元格文本验证（表格中所有 td）
    const cells = container.querySelectorAll("td");
    // 4 行 × 6 列 = 24 个 td
    expect(cells).toHaveLength(24);
    // 验证部分分数
    expect(screen.getByText("85")).toBeInTheDocument();
    expect(screen.getByText("92")).toBeInTheDocument();
  });

  it("渲染每科班级排名（rank/classSize 格式）", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    // 4 个科目各自的 rank/classSize = 8/45, 3/45, 5/45, 2/45
    expect(screen.getByText("8/45")).toBeInTheDocument();
    expect(screen.getByText("3/45")).toBeInTheDocument();
    expect(screen.getByText("5/45")).toBeInTheDocument();
    expect(screen.getByText("2/45")).toBeInTheDocument();
  });
});

describe("ReportCardView 总分与排名", () => {
  it("渲染总分与排名 section", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    expect(screen.getByLabelText("总分与排名")).toBeInTheDocument();
  });

  it("渲染总分（90）", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    // 总分标签
    expect(screen.getByText("总分")).toBeInTheDocument();
    // 总分值（90）— 注意 90 也可能出现在其他地方（如 classAverage），需要精确匹配
    const overallScoreSection = screen.getByLabelText("总分与排名");
    expect(overallScoreSection).toHaveTextContent("90");
  });

  it("渲染班级排名标签与数值（5）", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    // "班级排名" 同时出现在表头和总分排名 section
    expect(screen.getAllByText("班级排名")).toHaveLength(2);
    // 总分排名 section 中包含数值 5
    const statsSection = screen.getByLabelText("总分与排名");
    expect(statsSection).toHaveTextContent("5");
  });

  it("渲染班级人数（45）", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    expect(screen.getByText("班级人数")).toBeInTheDocument();
  });
});

describe("ReportCardView 教师评语", () => {
  it("渲染教师评语 section", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    expect(screen.getByLabelText("教师评语")).toBeInTheDocument();
  });

  it("渲染班主任评语", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    expect(screen.getByText("班主任评语")).toBeInTheDocument();
    expect(
      screen.getByText(
        "本学期学习态度认真，成绩稳中有进，望继续保持，加强薄弱环节",
      ),
    ).toBeInTheDocument();
  });

  it("渲染校长评语（当存在时）", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    expect(screen.getByText("校长评语")).toBeInTheDocument();
    expect(
      screen.getByText(
        "该生品学兼优，关心集体，乐于助人，下学期可担任班干部锻炼能力",
      ),
    ).toBeInTheDocument();
  });

  it("不渲染校长评语区块（当 headTeacherComment 缺失时）", () => {
    const noHeadComment: ReportCard = {
      ...mockReportCard,
      headTeacherComment: undefined,
    };
    render(<ReportCardView reportCard={noHeadComment} />);
    expect(screen.queryByText("校长评语")).not.toBeInTheDocument();
  });
});

describe("ReportCardView 打印按钮", () => {
  it("渲染打印按钮", () => {
    render(<ReportCardView reportCard={mockReportCard} />);
    expect(
      screen.getByRole("button", { name: "打印报告卡" }),
    ).toBeInTheDocument();
  });

  it("点击打印按钮调用 window.print", async () => {
    const user = userEvent.setup();
    const printSpy = vi.fn();
    Object.defineProperty(window, "print", {
      configurable: true,
      value: printSpy,
    });
    render(<ReportCardView reportCard={mockReportCard} />);
    await user.click(screen.getByRole("button", { name: "打印报告卡" }));
    expect(printSpy).toHaveBeenCalledTimes(1);
  });
});
