import { describe, it, expect } from "vitest";
import {
  mapParent,
  mapChild,
  mapClassInfo,
  mapGrade,
  mapHomework,
  mapExam,
  mapViewport,
  mapWeakness,
  mapTrend,
  mapAnalytics,
} from "../../src/aggregation/response-mapper.js";
import type {
  UserInfoDto,
  ChildDto,
  GradeDto,
  HomeworkDto,
  ExamDto,
  ViewportDto,
  StudentWeaknessDto,
  LearningTrendDto,
  ClassPerformanceDto,
} from "../../src/clients/dtos.js";

describe("Response Mapper", () => {
  describe("mapParent", () => {
    it("正确映射 UserInfoDto → ParentType", () => {
      const dto: UserInfoDto = {
        id: "parent-001",
        email: "parent@example.com",
        name: "王家长",
        roles: ["parent"],
        permissions: [],
      };
      const result = mapParent(dto);
      expect(result.id).toBe("parent-001");
      expect(result.email).toBe("parent@example.com");
      expect(result.name).toBe("王家长");
      expect(result.avatar).toBeNull();
      expect(result.roles).toEqual(["parent"]);
      expect(result.dataScope).toBe("CHILDREN");
    });
  });

  describe("mapChild", () => {
    it("正确映射 ChildDto → ChildType", () => {
      const dto: ChildDto = {
        id: "student-001",
        name: "李同学",
        grade: "三年级",
        classId: "class-001",
        className: "三年级1班",
        gradeId: "grade-003",
      };
      const result = mapChild(dto);
      expect(result.id).toBe("student-001");
      expect(result.name).toBe("李同学");
      expect(result.grade).toBe("三年级");
      expect(result.class.id).toBe("class-001");
      expect(result.class.name).toBe("三年级1班");
      expect(result.class.gradeId).toBe("grade-003");
    });
  });

  describe("mapClassInfo", () => {
    it("正确映射 ClassInfo", () => {
      const result = mapClassInfo({
        id: "class-001",
        name: "三年级1班",
        gradeId: "grade-003",
      });
      expect(result.id).toBe("class-001");
      expect(result.name).toBe("三年级1班");
      expect(result.gradeId).toBe("grade-003");
    });
  });

  describe("mapGrade", () => {
    it("正确映射 GradeDto → GradeType（score string → number）", () => {
      const dto: GradeDto = {
        id: "grade-001",
        studentId: "student-001",
        examId: "exam-001",
        homeworkId: "",
        score: "85.5",
        feedback: "数学表现良好",
        gradedBy: "teacher-001",
        createdAt: "2026-01-01T00:00:00.000Z",
        updatedAt: "2026-01-02T00:00:00.000Z",
      };
      const result = mapGrade(dto);
      expect(result.id).toBe("grade-001");
      expect(result.examId).toBe("exam-001");
      expect(result.score).toBe(85.5);
      expect(result.subject).toBe("数学");
      expect(result.examTitle).toBe("数学表现良好");
      expect(result.rank).toBeNull();
      expect(result.gradedAt).toBe("2026-01-02T00:00:00.000Z");
    });

    it("feedback 为空时 examTitle 为默认值", () => {
      const dto: GradeDto = {
        id: "grade-001",
        studentId: "student-001",
        examId: "exam-001",
        homeworkId: "",
        score: "90",
        feedback: "",
        gradedBy: "teacher-001",
        createdAt: "2026-01-01T00:00:00.000Z",
        updatedAt: "2026-01-02T00:00:00.000Z",
      };
      const result = mapGrade(dto);
      expect(result.examTitle).toBe("未命名考试");
      expect(result.subject).toBe("未知科目");
    });

    it("score 非数字时返回 0", () => {
      const dto: GradeDto = {
        id: "grade-001",
        studentId: "student-001",
        examId: "exam-001",
        homeworkId: "",
        score: "invalid",
        feedback: "语文表现良好",
        gradedBy: "teacher-001",
        createdAt: "2026-01-01T00:00:00.000Z",
        updatedAt: "2026-01-02T00:00:00.000Z",
      };
      const result = mapGrade(dto);
      expect(result.score).toBe(0);
      expect(result.subject).toBe("语文");
    });

    it("feedback 无科目前缀时 subject 为综合", () => {
      const dto: GradeDto = {
        id: "grade-001",
        studentId: "student-001",
        examId: "exam-001",
        homeworkId: "",
        score: "80",
        feedback: "表现不错",
        gradedBy: "teacher-001",
        createdAt: "2026-01-01T00:00:00.000Z",
        updatedAt: "2026-01-02T00:00:00.000Z",
      };
      const result = mapGrade(dto);
      expect(result.subject).toBe("综合");
    });
  });

  describe("mapHomework", () => {
    it("SUBMITTED 状态返回 submittedAt", () => {
      const dto: HomeworkDto = {
        id: "hw-001",
        classId: "class-001",
        title: "数学练习",
        description: "",
        dueDate: "2026-01-05T00:00:00.000Z",
        status: "SUBMITTED",
        createdBy: "teacher-001",
        createdAt: "2026-01-01T00:00:00.000Z",
        updatedAt: "2026-01-02T00:00:00.000Z",
      };
      const result = mapHomework(dto);
      expect(result.status).toBe("SUBMITTED");
      expect(result.submittedAt).toBe("2026-01-02T00:00:00.000Z");
    });

    it("GRADED 状态返回 submittedAt", () => {
      const dto: HomeworkDto = {
        id: "hw-001",
        classId: "class-001",
        title: "数学练习",
        description: "",
        dueDate: "2026-01-05T00:00:00.000Z",
        status: "GRADED",
        createdBy: "teacher-001",
        createdAt: "2026-01-01T00:00:00.000Z",
        updatedAt: "2026-01-03T00:00:00.000Z",
      };
      const result = mapHomework(dto);
      expect(result.submittedAt).toBe("2026-01-03T00:00:00.000Z");
    });

    it("NOT_SUBMITTED 状态 submittedAt 为 null", () => {
      const dto: HomeworkDto = {
        id: "hw-001",
        classId: "class-001",
        title: "数学练习",
        description: "",
        dueDate: "2026-01-05T00:00:00.000Z",
        status: "NOT_SUBMITTED",
        createdBy: "teacher-001",
        createdAt: "2026-01-01T00:00:00.000Z",
        updatedAt: "2026-01-02T00:00:00.000Z",
      };
      const result = mapHomework(dto);
      expect(result.submittedAt).toBeNull();
    });
  });

  describe("mapExam", () => {
    it("PUBLISHED 状态返回 publishedAt", () => {
      const dto: ExamDto = {
        id: "exam-001",
        classId: "class-001",
        title: "数学期中考试",
        description: "",
        examDate: "2026-02-01T00:00:00.000Z",
        duration: "90",
        totalScore: "100",
        status: "PUBLISHED",
        createdBy: "teacher-001",
        createdAt: "2026-01-01T00:00:00.000Z",
        updatedAt: "2026-01-15T00:00:00.000Z",
      };
      const result = mapExam(dto);
      expect(result.status).toBe("PUBLISHED");
      expect(result.publishedAt).toBe("2026-01-15T00:00:00.000Z");
    });

    it("DRAFT 状态 publishedAt 为 null", () => {
      const dto: ExamDto = {
        id: "exam-001",
        classId: "class-001",
        title: "数学期中考试",
        description: "",
        examDate: "2026-02-01T00:00:00.000Z",
        duration: "90",
        totalScore: "100",
        status: "DRAFT",
        createdBy: "teacher-001",
        createdAt: "2026-01-01T00:00:00.000Z",
        updatedAt: "2026-01-15T00:00:00.000Z",
      };
      const result = mapExam(dto);
      expect(result.publishedAt).toBeNull();
    });
  });

  describe("mapViewport", () => {
    it("正确映射 ViewportDto", () => {
      const dto: ViewportDto = {
        key: "dashboard",
        label: "首页",
        route: "/parent/dashboard",
        icon: "home",
        sortOrder: "1",
        requiredPermission: "parent:dashboard:view",
      };
      const result = mapViewport(dto);
      expect(result.key).toBe("dashboard");
      expect(result.label).toBe("首页");
      expect(result.icon).toBe("home");
      expect(result.requiredPermission).toBe("parent:dashboard:view");
    });

    it("icon 和 requiredPermission 可选", () => {
      const dto: ViewportDto = {
        key: "settings",
        label: "设置",
        route: "/parent/settings",
        sortOrder: "5",
      };
      const result = mapViewport(dto);
      expect(result.icon).toBeNull();
      expect(result.requiredPermission).toBeNull();
    });
  });

  describe("mapWeakness", () => {
    it("正确映射薄弱点列表", () => {
      const dto: StudentWeaknessDto = {
        studentId: "student-001",
        weakPoints: [
          { knowledgePointId: "kp-1", title: "分数加减法", mastery: 0.45 },
          { knowledgePointId: "kp-2", title: "阅读理解", mastery: 0.62 },
        ],
      };
      const result = mapWeakness(dto);
      expect(result).toHaveLength(2);
      expect(result[0]!.knowledgePointId).toBe("kp-1");
      expect(result[0]!.name).toBe("分数加减法");
      expect(result[0]!.masteryRate).toBe(0.45);
      expect(result[0]!.subject).toBe("综合");
    });

    it("空薄弱点列表", () => {
      const dto: StudentWeaknessDto = {
        studentId: "student-001",
        weakPoints: [],
      };
      const result = mapWeakness(dto);
      expect(result).toHaveLength(0);
    });
  });

  describe("mapTrend", () => {
    it("正确映射趋势点（int64 ms → ISO string）", () => {
      const dto: LearningTrendDto = {
        studentId: "student-001",
        points: [
          { date: 1735689600000, score: 80 },
          { date: 1735776000000, score: 85 },
        ],
      };
      const result = mapTrend(dto);
      expect(result).toHaveLength(2);
      expect(result[0]!.score).toBe(80);
      expect(typeof result[0]!.date).toBe("string");
      expect(new Date(result[0]!.date).getTime()).toBe(1735689600000);
      expect(result[0]!.subject).toBeNull();
    });
  });

  describe("mapAnalytics", () => {
    it("正确计算 classRank（降序排名）", () => {
      const weakness: StudentWeaknessDto = {
        studentId: "student-001",
        weakPoints: [],
      };
      const trend: LearningTrendDto = {
        studentId: "student-001",
        points: [],
      };
      const classPerf: ClassPerformanceDto = {
        classId: "class-001",
        averageScore: 82.5,
        passRate: 0.9,
        scores: [
          { studentId: "student-001", score: 85, grade: "A" },
          { studentId: "student-002", score: 92, grade: "A" },
          { studentId: "student-003", score: 65, grade: "C" },
        ],
      };
      const result = mapAnalytics("student-001", weakness, trend, classPerf);
      expect(result.childId).toBe("student-001");
      expect(result.classAverage).toBe(82.5);
      const sorted = [...classPerf.scores].sort((a, b) => b.score - a.score);
      const idx = sorted.findIndex((s) => s.studentId === "student-001");
      expect(result.classRank).toBe(idx + 1);
    });

    it("classPerf 为 null 时 classRank 和 classAverage 为 null", () => {
      const weakness: StudentWeaknessDto = {
        studentId: "student-001",
        weakPoints: [],
      };
      const trend: LearningTrendDto = {
        studentId: "student-001",
        points: [],
      };
      const result = mapAnalytics("student-001", weakness, trend, null);
      expect(result.classRank).toBeNull();
      expect(result.classAverage).toBeNull();
    });

    it("childId 不在 scores 中时 classRank 为 null", () => {
      const weakness: StudentWeaknessDto = {
        studentId: "student-001",
        weakPoints: [],
      };
      const trend: LearningTrendDto = {
        studentId: "student-001",
        points: [],
      };
      const classPerf: ClassPerformanceDto = {
        classId: "class-001",
        averageScore: 80,
        passRate: 0.9,
        scores: [
          { studentId: "student-002", score: 90, grade: "A" },
          { studentId: "student-003", score: 70, grade: "B" },
        ],
      };
      const result = mapAnalytics("student-001", weakness, trend, classPerf);
      expect(result.classRank).toBeNull();
      expect(result.classAverage).toBe(80);
    });

    it("scores 为空数组时 classRank 为 null", () => {
      const weakness: StudentWeaknessDto = {
        studentId: "student-001",
        weakPoints: [],
      };
      const trend: LearningTrendDto = {
        studentId: "student-001",
        points: [],
      };
      const classPerf: ClassPerformanceDto = {
        classId: "class-001",
        averageScore: 0,
        passRate: 0,
        scores: [],
      };
      const result = mapAnalytics("student-001", weakness, trend, classPerf);
      expect(result.classRank).toBeNull();
    });
  });
});
