// ChildDetailPanel 组件单测
// 依据：02-architecture-design.md §15 组件设计
// 覆盖：Tab 导航 / Tab 切换 / overview / homework / grades / exams / schedule 五个视图

import { describe, it, expect, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { ChildDetailPanel } from "./ChildDetailPanel";
import type { ChildDetail } 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>
  ),
}));

const mockChildDetail: ChildDetail = {
  childId: "student-001",
  basicInfo: {
    name: "张小明",
    avatar: "https://example.com/avatar.png",
    grade: "grade.7",
    className: "初一(1)班",
    schoolName: "实验中学",
    relation: "父亲",
  },
  todaySchedule: [
    {
      id: "sch-today-1",
      dayOfWeek: 1,
      period: 1,
      subject: "数学",
      teacherName: "王老师",
      classroom: "初一(1)班教室",
      startTime: "08:00",
      endTime: "08:45",
    },
    {
      id: "sch-today-2",
      dayOfWeek: 1,
      period: 2,
      subject: "语文",
      teacherName: "李老师",
      classroom: "初一(1)班教室",
      startTime: "08:55",
      endTime: "09:40",
    },
  ],
  weeklySchedule: [
    {
      id: "sch-w-1",
      dayOfWeek: 1,
      period: 1,
      subject: "数学",
      teacherName: "王老师",
      classroom: "初一(1)班教室",
      startTime: "08:00",
      endTime: "08:45",
    },
    {
      id: "sch-w-2",
      dayOfWeek: 2,
      period: 1,
      subject: "英语",
      teacherName: "张老师",
      classroom: "初一(1)班教室",
      startTime: "08:00",
      endTime: "08:45",
    },
  ],
  homeworkSummary: {
    pendingCount: 3,
    overdueCount: 1,
    submittedCount: 5,
    gradedCount: 8,
  },
  gradeSummary: {
    avgScore: 90,
    classRank: 5,
    classSize: 45,
    trend: "up",
  },
  examResults: {
    upcoming: 2,
    completed: 4,
    avgScore: 88,
  },
};

describe("ChildDetailPanel Tab 导航", () => {
  it("渲染 5 个 Tab（概览/作业/成绩/考试/课表）", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="overview"
        onTabChange={vi.fn()}
      />,
    );
    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();
    expect(screen.getByRole("tab", { name: "课表" })).toBeInTheDocument();
  });

  it("activeTab=overview 时概览 tab 选中", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="overview"
        onTabChange={vi.fn()}
      />,
    );
    expect(screen.getByRole("tab", { name: "概览" })).toHaveAttribute("aria-selected", "true");
    expect(screen.getByRole("tab", { name: "作业" })).toHaveAttribute("aria-selected", "false");
  });

  it("点击 Tab 调用 onTabChange", async () => {
    const user = userEvent.setup();
    const onTabChange = vi.fn();
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="overview"
        onTabChange={onTabChange}
      />,
    );
    await user.click(screen.getByRole("tab", { name: "作业" }));
    expect(onTabChange).toHaveBeenCalledWith("homework");
  });

  it("点击成绩 Tab 调用 onTabChange 传 grades", async () => {
    const user = userEvent.setup();
    const onTabChange = vi.fn();
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="overview"
        onTabChange={onTabChange}
      />,
    );
    await user.click(screen.getByRole("tab", { name: "成绩" }));
    expect(onTabChange).toHaveBeenCalledWith("grades");
  });
});

describe("ChildDetailPanel overview Tab", () => {
  it("渲染三个 Section（作业摘要/成绩摘要/今日课表）", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="overview"
        onTabChange={vi.fn()}
      />,
    );
    expect(screen.getByText("作业摘要")).toBeInTheDocument();
    expect(screen.getByText("成绩摘要")).toBeInTheDocument();
    expect(screen.getByText("今日课表")).toBeInTheDocument();
  });

  it("渲染作业摘要数据（待完成/已逾期/已提交/已评分）", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="overview"
        onTabChange={vi.fn()}
      />,
    );
    expect(screen.getByText("待完成")).toBeInTheDocument();
    expect(screen.getByText("已逾期")).toBeInTheDocument();
    expect(screen.getByText("已提交")).toBeInTheDocument();
    expect(screen.getByText("已评分")).toBeInTheDocument();
    // 验证数值（3/1/5/8）
    expect(screen.getByText("3")).toBeInTheDocument();
    expect(screen.getByText("1")).toBeInTheDocument();
    expect(screen.getByText("5")).toBeInTheDocument();
    expect(screen.getByText("8")).toBeInTheDocument();
  });

  it("渲染成绩摘要数据（平均分/班级排名/趋势）", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="overview"
        onTabChange={vi.fn()}
      />,
    );
    expect(screen.getByText("平均分")).toBeInTheDocument();
    expect(screen.getByText("班级排名")).toBeInTheDocument();
    expect(screen.getByText("趋势")).toBeInTheDocument();
    // 趋势 up → "↑ 上升"
    expect(screen.getByText("↑ 上升")).toBeInTheDocument();
  });

  it("渲染今日课表数据", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="overview"
        onTabChange={vi.fn()}
      />,
    );
    expect(screen.getByText("数学")).toBeInTheDocument();
    expect(screen.getByText("语文")).toBeInTheDocument();
    // 教师姓名与教室渲染在同一 span（如 "王老师 · 初一(1)班教室"），用 regex 验证
    expect(screen.getByText(/王老师/)).toBeInTheDocument();
    expect(screen.getByText(/李老师/)).toBeInTheDocument();
  });
});

describe("ChildDetailPanel homework Tab", () => {
  it("渲染作业摘要 Section", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="homework"
        onTabChange={vi.fn()}
      />,
    );
    expect(screen.getByText("作业摘要")).toBeInTheDocument();
  });

  it("渲染查看全部作业链接", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="homework"
        onTabChange={vi.fn()}
      />,
    );
    const link = screen.getByRole("link", { name: /查看全部作业/ });
    expect(link).toHaveAttribute("href", "/parent/homework");
  });
});

describe("ChildDetailPanel grades Tab", () => {
  it("渲染成绩摘要 Section", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="grades"
        onTabChange={vi.fn()}
      />,
    );
    expect(screen.getByText("成绩摘要")).toBeInTheDocument();
  });

  it("渲染查看全部成绩链接", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="grades"
        onTabChange={vi.fn()}
      />,
    );
    const link = screen.getByRole("link", { name: /查看全部成绩/ });
    expect(link).toHaveAttribute("href", "/parent/grades");
  });
});

describe("ChildDetailPanel exams Tab", () => {
  it("渲染考试摘要 Section", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="exams"
        onTabChange={vi.fn()}
      />,
    );
    expect(screen.getByText("考试摘要")).toBeInTheDocument();
  });

  it("渲染考试统计数据（待考/已完成/平均分）", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="exams"
        onTabChange={vi.fn()}
      />,
    );
    expect(screen.getByText("待考")).toBeInTheDocument();
    expect(screen.getByText("已完成")).toBeInTheDocument();
    expect(screen.getByText("平均分")).toBeInTheDocument();
  });

  it("渲染查看全部考试链接", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="exams"
        onTabChange={vi.fn()}
      />,
    );
    const link = screen.getByRole("link", { name: /查看全部考试/ });
    expect(link).toHaveAttribute("href", "/parent/exams");
  });
});

describe("ChildDetailPanel schedule Tab", () => {
  it("渲染今日课表 Section", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="schedule"
        onTabChange={vi.fn()}
      />,
    );
    expect(screen.getByText(/今日课表/)).toBeInTheDocument();
  });

  it("渲染周课表 Section", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="schedule"
        onTabChange={vi.fn()}
      />,
    );
    expect(screen.getByText("周课表")).toBeInTheDocument();
  });

  it("渲染周课表分组（周一/周二）", () => {
    render(
      <ChildDetailPanel
        childDetail={mockChildDetail}
        activeTab="schedule"
        onTabChange={vi.fn()}
      />,
    );
    // 周课表含 dayOfWeek 1（周一）和 2（周二）
    expect(screen.getByText("周一")).toBeInTheDocument();
    expect(screen.getByText("周二")).toBeInTheDocument();
  });
});

describe("ChildDetailPanel 空态", () => {
  it("今日课表为空时显示今日无课程", () => {
    const emptySchedule: ChildDetail = {
      ...mockChildDetail,
      todaySchedule: [],
    };
    render(
      <ChildDetailPanel
        childDetail={emptySchedule}
        activeTab="overview"
        onTabChange={vi.fn()}
      />,
    );
    expect(screen.getByText("今日无课程")).toBeInTheDocument();
  });

  it("周课表为空时显示暂无周课表", () => {
    const emptyWeekly: ChildDetail = {
      ...mockChildDetail,
      weeklySchedule: [],
    };
    render(
      <ChildDetailPanel
        childDetail={emptyWeekly}
        activeTab="schedule"
        onTabChange={vi.fn()}
      />,
    );
    expect(screen.getByText("暂无周课表")).toBeInTheDocument();
  });
});

describe("ChildDetailPanel 趋势显示", () => {
  it("gradeSummary.trend=down 时显示 ↓ 下降", () => {
    const downTrend: ChildDetail = {
      ...mockChildDetail,
      gradeSummary: {
        ...mockChildDetail.gradeSummary,
        trend: "down",
      },
    };
    render(
      <ChildDetailPanel
        childDetail={downTrend}
        activeTab="overview"
        onTabChange={vi.fn()}
      />,
    );
    expect(screen.getByText("↓ 下降")).toBeInTheDocument();
  });

  it("gradeSummary.trend=stable 时显示 → 平稳", () => {
    const stableTrend: ChildDetail = {
      ...mockChildDetail,
      gradeSummary: {
        ...mockChildDetail.gradeSummary,
        trend: "stable",
      },
    };
    render(
      <ChildDetailPanel
        childDetail={stableTrend}
        activeTab="overview"
        onTabChange={vi.fn()}
      />,
    );
    expect(screen.getByText("→ 平稳")).toBeInTheDocument();
  });
});
