// ChildSummaryCard 组件单测
// 依据：02-architecture-design.md §15.4 ChildSummaryCard 设计
// 覆盖：指标网格 / 成绩趋势 / 即将到来事件 / 趋势标签 fallback

import { describe, it, expect, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import { ChildSummaryCard } from "./ChildSummaryCard";
import type { ChildSummary } from "@/types";

// mock next/link 为普通 <a>
vi.mock("next/link", () => ({
  default: ({
    href,
    children,
    ...rest
  }: {
    href: string;
    children: React.ReactNode;
    [key: string]: unknown;
  }) => (
    <a href={href} {...rest}>
      {children}
    </a>
  ),
}));

function makeSummary(overrides: Partial<ChildSummary> = {}): ChildSummary {
  return {
    childId: "student-001",
    avgScore: 90,
    classRank: 5,
    classSize: 45,
    attendanceRate: 0.96,
    pendingHomeworkCount: 3,
    recentGradeTrend: "up",
    recentScores: [
      {
        examId: "exam-001",
        examName: "期中数学",
        examDate: "2026-03-15T09:00:00Z",
        subject: "数学",
        studentScore: 92,
        classAverage: 78,
        gradeLevel: "A",
      },
      {
        examId: "exam-002",
        examName: "期中语文",
        examDate: "2026-03-16T09:00:00Z",
        subject: "语文",
        studentScore: 85,
        gradeLevel: "B",
      },
    ],
    upcomingEvents: [
      {
        id: "event-001",
        type: "exam",
        title: "期末数学考试",
        dueDate: "2026-07-20T09:00:00Z",
      },
    ],
    ...overrides,
  };
}

describe("ChildSummaryCard 指标网格", () => {
  it("渲染平均分", () => {
    render(<ChildSummaryCard summary={makeSummary()} />);
    expect(screen.getByText("平均分")).toBeInTheDocument();
    expect(screen.getByText("90")).toBeInTheDocument();
  });

  it("渲染班级排名（rank / size）", () => {
    render(<ChildSummaryCard summary={makeSummary()} />);
    expect(screen.getByText("班级排名")).toBeInTheDocument();
    expect(screen.getByText("5 / 45")).toBeInTheDocument();
  });

  it("渲染出勤率（百分比）", () => {
    render(<ChildSummaryCard summary={makeSummary()} />);
    expect(screen.getByText("出勤率")).toBeInTheDocument();
    // 0.96 → 96%
    expect(screen.getByText(/96/)).toBeInTheDocument();
  });

  it("渲染待完成作业数", () => {
    render(
      <ChildSummaryCard summary={makeSummary({ pendingHomeworkCount: 3 })} />,
    );
    expect(screen.getByText("待完成作业")).toBeInTheDocument();
    expect(screen.getByText("3")).toBeInTheDocument();
  });

  it("待完成作业 > 0 时指标卡片高亮（border-warning）", () => {
    const { container } = render(
      <ChildSummaryCard summary={makeSummary({ pendingHomeworkCount: 2 })} />,
    );
    const metricCards = container.querySelectorAll(".border-warning");
    expect(metricCards.length).toBeGreaterThan(0);
  });

  it("待完成作业 = 0 时指标卡片不高亮", () => {
    const { container } = render(
      <ChildSummaryCard summary={makeSummary({ pendingHomeworkCount: 0 })} />,
    );
    const metricCards = container.querySelectorAll(".border-warning");
    expect(metricCards.length).toBe(0);
  });
});

describe("ChildSummaryCard 成绩趋势", () => {
  it("渲染成绩趋势标题", () => {
    render(<ChildSummaryCard summary={makeSummary()} />);
    expect(screen.getByText("成绩趋势")).toBeInTheDocument();
  });

  it("trend=up 显示上升", () => {
    render(
      <ChildSummaryCard summary={makeSummary({ recentGradeTrend: "up" })} />,
    );
    expect(screen.getByText("上升")).toBeInTheDocument();
  });

  it("trend=down 显示下降", () => {
    render(
      <ChildSummaryCard summary={makeSummary({ recentGradeTrend: "down" })} />,
    );
    expect(screen.getByText("下降")).toBeInTheDocument();
  });

  it("trend=stable 显示稳定", () => {
    render(
      <ChildSummaryCard
        summary={makeSummary({ recentGradeTrend: "stable" })}
      />,
    );
    expect(screen.getByText("稳定")).toBeInTheDocument();
  });

  it("trend 为未知值时回退到默认稳定（防御性兜底，类型断言仅用于测试）", () => {
    // 测试中用 as 模拟脏数据触发 DEFAULT_TREND 兜底分支
    const summary = makeSummary({
      recentGradeTrend: "unknown" as ChildSummary["recentGradeTrend"],
    });
    render(<ChildSummaryCard summary={summary} />);
    expect(screen.getByText("稳定")).toBeInTheDocument();
  });

  it("渲染最近成绩列表（含 subject 与 examName）", () => {
    render(<ChildSummaryCard summary={makeSummary()} />);
    expect(screen.getByText("数学")).toBeInTheDocument();
    expect(screen.getByText("期中数学")).toBeInTheDocument();
    expect(screen.getByText("语文")).toBeInTheDocument();
  });

  it("渲染学生分数", () => {
    render(<ChildSummaryCard summary={makeSummary()} />);
    expect(screen.getByText("92")).toBeInTheDocument();
    expect(screen.getByText("85")).toBeInTheDocument();
  });

  it("有 classAverage 时显示班均", () => {
    render(<ChildSummaryCard summary={makeSummary()} />);
    expect(screen.getByText(/班均/)).toBeInTheDocument();
    expect(screen.getByText(/班均.*78/)).toBeInTheDocument();
  });

  it("最多显示 5 条最近成绩", () => {
    const sixScores = Array.from({ length: 6 }, (_, i) => ({
      examId: `exam-${i}`,
      examName: `测验${i}`,
      examDate: "2026-03-15T09:00:00Z",
      subject: `科目${i}`,
      studentScore: 80 + i,
      gradeLevel: "B" as const,
    }));
    render(
      <ChildSummaryCard summary={makeSummary({ recentScores: sixScores })} />,
    );
    // 第 0..4 条显示，第 5 条不显示
    expect(screen.getByText("科目0")).toBeInTheDocument();
    expect(screen.getByText("科目4")).toBeInTheDocument();
    expect(screen.queryByText("科目5")).not.toBeInTheDocument();
  });
});

describe("ChildSummaryCard 即将到来事件", () => {
  it("有 upcomingEvents 时渲染即将到来区域", () => {
    render(<ChildSummaryCard summary={makeSummary()} />);
    expect(screen.getByText("即将到来")).toBeInTheDocument();
    expect(screen.getByText("期末数学考试")).toBeInTheDocument();
  });

  it("upcomingEvents 为空数组时不渲染即将到来区域", () => {
    render(<ChildSummaryCard summary={makeSummary({ upcomingEvents: [] })} />);
    expect(screen.queryByText("即将到来")).not.toBeInTheDocument();
  });

  it("upcomingEvents 为 undefined 时不渲染即将到来区域", () => {
    render(
      <ChildSummaryCard summary={makeSummary({ upcomingEvents: undefined })} />,
    );
    expect(screen.queryByText("即将到来")).not.toBeInTheDocument();
  });

  it("渲染多个即将到来事件", () => {
    const summary = makeSummary({
      upcomingEvents: [
        {
          id: "event-001",
          type: "exam",
          title: "期末数学考试",
          dueDate: "2026-07-20T09:00:00Z",
        },
        {
          id: "event-002",
          type: "homework",
          title: "物理实验报告",
          dueDate: "2026-07-12T23:59:59Z",
        },
      ],
    });
    render(<ChildSummaryCard summary={summary} />);
    expect(screen.getByText("期末数学考试")).toBeInTheDocument();
    expect(screen.getByText("物理实验报告")).toBeInTheDocument();
  });
});

describe("ChildSummaryCard 趋势图标", () => {
  it("trend=up 显示上升箭头", () => {
    render(
      <ChildSummaryCard summary={makeSummary({ recentGradeTrend: "up" })} />,
    );
    expect(screen.getByText("↑")).toBeInTheDocument();
    expect(screen.getByText("上升")).toBeInTheDocument();
  });

  it("trend=down 显示下降箭头", () => {
    render(
      <ChildSummaryCard summary={makeSummary({ recentGradeTrend: "down" })} />,
    );
    expect(screen.getByText("↓")).toBeInTheDocument();
    expect(screen.getByText("下降")).toBeInTheDocument();
  });

  it("trend=stable 显示稳定箭头", () => {
    render(
      <ChildSummaryCard
        summary={makeSummary({ recentGradeTrend: "stable" })}
      />,
    );
    expect(screen.getByText("→")).toBeInTheDocument();
    expect(screen.getByText("稳定")).toBeInTheDocument();
  });
});

describe("ChildSummaryCard 逾期作业徽标", () => {
  it("pendingHomeworkCount > 0 时显示待办徽标", () => {
    render(
      <ChildSummaryCard summary={makeSummary({ pendingHomeworkCount: 3 })} />,
    );
    expect(screen.getByText(/3 份待办/)).toBeInTheDocument();
  });

  it("pendingHomeworkCount = 0 时不显示待办徽标", () => {
    render(
      <ChildSummaryCard summary={makeSummary({ pendingHomeworkCount: 0 })} />,
    );
    expect(screen.queryByText(/份待办/)).not.toBeInTheDocument();
  });
});

describe("ChildSummaryCard 跳转链接", () => {
  it("卡片渲染为链接，指向子女详情页", () => {
    render(<ChildSummaryCard summary={makeSummary()} />);
    const link = screen.getByRole("link");
    expect(link).toHaveAttribute("href", "/parent/children/student-001");
  });
});
