import { Injectable, NotFoundException, ForbiddenException, ConflictException, Logger, BadRequestException } from '@nestjs/common';
import { PrismaService } from '../../database/prisma.service';
import { CreateTeacherDto, UpdateTeacherDto } from './dto/create-teacher.dto';
import { CreateStudentDto, UpdateStudentDto } from './dto/create-student.dto';
import { CreateClassDto, UpdateClassDto } from './dto/create-class.dto';
import { AddClassTeacherDto, UpdateClassTeacherDto, TransferStudentDto } from './dto/class-teacher.dto';
import { CreateScheduleDto, UpdateScheduleDto, QueryScheduleDto, TimetableQueryDto } from './dto/schedule.dto';
import * as bcrypt from 'bcrypt';
import * as xlsx from 'xlsx';

@Injectable()
export class SchoolService {
  private readonly logger = new Logger(SchoolService.name);

  constructor(private prisma: PrismaService) {}

  // ==================== 工具方法 ====================

  private parseJsonArray(value: any): any[] {
    if (!value) return [];
    if (typeof value === 'string') {
      try {
        return JSON.parse(value);
      } catch {
        return [];
      }
    }
    return Array.isArray(value) ? value : [];
  }

  // ==================== 教师管理 ====================

  async findTeachers(tenantId: number, query: any) {
    const { page = 1, pageSize = 10, keyword, status } = query;

    const skip = (page - 1) * pageSize;
    const take = +pageSize;

    const where: any = {
      tenantId: tenantId,
    };

    if (keyword) {
      where.OR = [
        { name: { contains: keyword } },
        { phone: { contains: keyword } },
        { loginAccount: { contains: keyword } },
      ];
    }

    if (status) {
      where.status = status;
    }

    const [items, total] = await Promise.all([
      this.prisma.teacher.findMany({
        where,
        skip,
        take,
        orderBy: { createdAt: 'desc' },
        include: {
          classes: {
            select: {
              id: true,
              name: true,
            },
          },
        },
      }),
      this.prisma.teacher.count({ where }),
    ]);

    // 获取每个教师的班级名称
    const parsedItems = items.map((teacher) => ({
      ...teacher,
      classIds: this.parseJsonArray(teacher.classIds),
      classNames: teacher.classes.map((c) => c.name).join(', '),
      passwordHash: undefined,
    }));

    return {
      items: parsedItems,
      total,
      page: +page,
      pageSize: +pageSize,
    };
  }

  async findTeacher(tenantId: number, id: number) {
    const teacher = await this.prisma.teacher.findFirst({
      where: {
        id: id,
        tenantId: tenantId,
      },
      include: {
        classes: {
          select: {
            id: true,
            name: true,
          },
        },
      },
    });

    if (!teacher) {
      throw new NotFoundException('教师不存在');
    }

    return {
      ...teacher,
      classIds: this.parseJsonArray(teacher.classIds),
      classNames: teacher.classes.map((c) => c.name).join(', '),
      passwordHash: undefined,
    };
  }

  async createTeacher(tenantId: number, dto: CreateTeacherDto) {
    // 检查配额
    const tenant = await this.prisma.tenant.findUnique({
      where: { id: tenantId },
    });

    if (!tenant) {
      throw new NotFoundException('学校不存在');
    }

    const teacherCount = await this.prisma.teacher.count({
      where: { tenantId: tenantId },
    });

    if (teacherCount >= tenant.teacherQuota) {
      throw new ForbiddenException('教师配额已满，无法添加更多教师');
    }

    // 检查账号是否已存在
    const existingTeacher = await this.prisma.teacher.findUnique({
      where: { loginAccount: dto.loginAccount },
    });

    if (existingTeacher) {
      throw new ConflictException('登录账号已存在');
    }

    // 加密密码
    const passwordHash = await bcrypt.hash(dto.password || '123456', 10);

    // 创建教师
    const teacher = await this.prisma.teacher.create({
      data: {
        tenantId: tenantId,
        name: dto.name,
        phone: dto.phone,
        email: dto.email,
        loginAccount: dto.loginAccount,
        passwordHash: passwordHash,
        classIds: JSON.stringify(dto.classIds || []),
        status: 'ACTIVE',
      },
      include: {
        classes: {
          select: {
            id: true,
            name: true,
          },
        },
      },
    });

    // 更新教师负责的班级
    if (dto.classIds && dto.classIds.length > 0) {
      await this.prisma.class.updateMany({
        where: {
          id: { in: dto.classIds },
          tenantId: tenantId,
        },
        data: {
          teacherId: teacher.id,
        },
      });
    }

    // 更新租户教师数量
    await this.prisma.tenant.update({
      where: { id: tenantId },
      data: {
        teacherCount: { increment: 1 },
      },
    });

    this.logger.log(`Teacher created: ${teacher.id} by tenant ${tenantId}`);

    return {
      ...teacher,
      classIds: this.parseJsonArray(teacher.classIds),
      classNames: teacher.classes.map((c) => c.name).join(', '),
      passwordHash: undefined,
    };
  }

  async updateTeacher(tenantId: number, id: number, dto: UpdateTeacherDto) {
    // 检查教师是否存在
    const existingTeacher = await this.prisma.teacher.findFirst({
      where: {
        id: id,
        tenantId: tenantId,
      },
    });

    if (!existingTeacher) {
      throw new NotFoundException('教师不存在');
    }

    // 更新教师
    const teacher = await this.prisma.teacher.update({
      where: { id: id },
      data: {
        name: dto.name,
        phone: dto.phone,
        email: dto.email,
        classIds: dto.classIds ? JSON.stringify(dto.classIds) : undefined,
      },
      include: {
        classes: {
          select: {
            id: true,
            name: true,
          },
        },
      },
    });

    // 更新班级的 teacherId
    // 首先清除旧的关联
    await this.prisma.class.updateMany({
      where: {
        teacherId: id,
        tenantId: tenantId,
      },
      data: {
        teacherId: null,
      },
    });

    // 设置新的关联
    if (dto.classIds && dto.classIds.length > 0) {
      await this.prisma.class.updateMany({
        where: {
          id: { in: dto.classIds },
          tenantId: tenantId,
        },
        data: {
          teacherId: id,
        },
      });
    }

    this.logger.log(`Teacher updated: ${id}`);

    return {
      ...teacher,
      classIds: this.parseJsonArray(teacher.classIds),
      classNames: teacher.classes.map((c) => c.name).join(', '),
      passwordHash: undefined,
    };
  }

  async deleteTeacher(tenantId: number, id: number) {
    // 检查教师是否存在
    const teacher = await this.prisma.teacher.findFirst({
      where: {
        id: id,
        tenantId: tenantId,
      },
    });

    if (!teacher) {
      throw new NotFoundException('教师不存在');
    }

    // 删除教师（会级联删除相关数据）
    await this.prisma.teacher.delete({
      where: { id: id },
    });

    // 更新租户教师数量
    await this.prisma.tenant.update({
      where: { id: tenantId },
      data: {
        teacherCount: { decrement: 1 },
      },
    });

    this.logger.log(`Teacher deleted: ${id}`);

    return { message: '删除成功' };
  }

  async resetTeacherPassword(tenantId: number, id: number) {
    // 检查教师是否存在
    const teacher = await this.prisma.teacher.findFirst({
      where: {
        id: id,
        tenantId: tenantId,
      },
    });

    if (!teacher) {
      throw new NotFoundException('教师不存在');
    }

    // 生成临时密码
    const tempPassword = Math.random().toString(36).slice(-8);
    const passwordHash = await bcrypt.hash(tempPassword, 10);

    // 更新密码
    await this.prisma.teacher.update({
      where: { id: id },
      data: {
        passwordHash: passwordHash,
      },
    });

    this.logger.log(`Teacher password reset: ${id}`);

    return { tempPassword };
  }

  // ==================== 学生管理 ====================

  async findStudents(tenantId: number, query: any) {
    const { page = 1, pageSize = 10, classId, keyword } = query;

    const skip = (page - 1) * pageSize;
    const take = +pageSize;

    const where: any = {
      tenantId: tenantId,
    };

    if (classId) {
      where.classId = +classId;
    }

    if (keyword) {
      where.OR = [
        { name: { contains: keyword } },
        { parentName: { contains: keyword } },
        { parentPhone: { contains: keyword } },
      ];
    }

    const [items, total] = await Promise.all([
      this.prisma.student.findMany({
        where,
        skip,
        take,
        orderBy: { createdAt: 'desc' },
        include: {
          class: {
            select: {
              id: true,
              name: true,
            },
          },
        },
      }),
      this.prisma.student.count({ where }),
    ]);

    const parsedItems = items.map((student) => ({
      ...student,
      className: student.class?.name,
    }));

    return {
      items: parsedItems,
      total,
      page: +page,
      pageSize: +pageSize,
    };
  }

  async findStudent(tenantId: number, id: number) {
    const student = await this.prisma.student.findFirst({
      where: {
        id: id,
        tenantId: tenantId,
      },
      include: {
        class: {
          select: {
            id: true,
            name: true,
          },
        },
      },
    });

    if (!student) {
      throw new NotFoundException('学生不存在');
    }

    return {
      ...student,
      className: student.class?.name,
    };
  }

  async createStudent(tenantId: number, dto: CreateStudentDto) {
    // 检查配额
    const tenant = await this.prisma.tenant.findUnique({
      where: { id: tenantId },
    });

    if (!tenant) {
      throw new NotFoundException('学校不存在');
    }

    const studentCount = await this.prisma.student.count({
      where: { tenantId: tenantId },
    });

    if (studentCount >= tenant.studentQuota) {
      throw new ForbiddenException('学生配额已满，无法添加更多学生');
    }

    // 检查班级是否存在
    const classEntity = await this.prisma.class.findFirst({
      where: {
        id: dto.classId,
        tenantId: tenantId,
      },
    });

    if (!classEntity) {
      throw new NotFoundException('班级不存在');
    }

    // 创建学生
    const student = await this.prisma.student.create({
      data: {
        tenantId: tenantId,
        classId: dto.classId,
        name: dto.name,
        gender: dto.gender,
        birthDate: dto.birthDate ? new Date(dto.birthDate) : null,
        parentName: dto.parentName,
        parentPhone: dto.parentPhone,
      },
      include: {
        class: {
          select: {
            id: true,
            name: true,
          },
        },
      },
    });

    // 更新班级学生数量
    await this.prisma.class.update({
      where: { id: dto.classId },
      data: {
        studentCount: { increment: 1 },
      },
    });

    // 更新租户学生数量
    await this.prisma.tenant.update({
      where: { id: tenantId },
      data: {
        studentCount: { increment: 1 },
      },
    });

    this.logger.log(`Student created: ${student.id} by tenant ${tenantId}`);

    return {
      ...student,
      className: student.class?.name,
    };
  }

  async updateStudent(tenantId: number, id: number, dto: UpdateStudentDto) {
    // 检查学生是否存在
    const existingStudent = await this.prisma.student.findFirst({
      where: {
        id: id,
        tenantId: tenantId,
      },
    });

    if (!existingStudent) {
      throw new NotFoundException('学生不存在');
    }

    // 如果要更换班级，检查新班级是否存在
    if (dto.classId && dto.classId !== existingStudent.classId) {
      const newClass = await this.prisma.class.findFirst({
        where: {
          id: dto.classId,
          tenantId: tenantId,
        },
      });

      if (!newClass) {
        throw new NotFoundException('新班级不存在');
      }
    }

    // 更新学生
    const student = await this.prisma.student.update({
      where: { id: id },
      data: {
        name: dto.name,
        gender: dto.gender,
        birthDate: dto.birthDate ? new Date(dto.birthDate) : undefined,
        classId: dto.classId,
        parentName: dto.parentName,
        parentPhone: dto.parentPhone,
      },
      include: {
        class: {
          select: {
            id: true,
            name: true,
          },
        },
      },
    });

    // 如果班级变更，更新班级学生数量
    if (dto.classId && dto.classId !== existingStudent.classId) {
      await this.prisma.class.update({
        where: { id: existingStudent.classId },
        data: {
          studentCount: { decrement: 1 },
        },
      });

      await this.prisma.class.update({
        where: { id: dto.classId },
        data: {
          studentCount: { increment: 1 },
        },
      });
    }

    this.logger.log(`Student updated: ${id}`);

    return {
      ...student,
      className: student.class?.name,
    };
  }

  async deleteStudent(tenantId: number, id: number) {
    // 检查学生是否存在
    const student = await this.prisma.student.findFirst({
      where: {
        id: id,
        tenantId: tenantId,
      },
    });

    if (!student) {
      throw new NotFoundException('学生不存在');
    }

    const classId = student.classId;

    // 删除学生（会级联删除相关数据）
    await this.prisma.student.delete({
      where: { id: id },
    });

    // 更新班级学生数量
    await this.prisma.class.update({
      where: { id: classId },
      data: {
        studentCount: { decrement: 1 },
      },
    });

    // 更新租户学生数量
    await this.prisma.tenant.update({
      where: { id: tenantId },
      data: {
        studentCount: { decrement: 1 },
      },
    });

    this.logger.log(`Student deleted: ${id}`);

    return { message: '删除成功' };
  }

  async importStudents(tenantId: number, studentsData: any[], defaultClassId?: number) {
    let success = 0;
    let failed = 0;
    const errors: Array<{ row: number; message: string }> = [];

    for (let i = 0; i < studentsData.length; i++) {
      const data = studentsData[i];
      try {
        const classId = data.classId || defaultClassId;
        if (!classId) {
          throw new Error('未指定班级');
        }

        await this.createStudent(tenantId, {
          name: data.name,
          gender: data.gender || '男',
          birthDate: data.birthDate,
          classId: classId,
          parentName: data.parentName,
          parentPhone: data.parentPhone,
        });
        success++;
      } catch (error: any) {
        failed++;
        errors.push({
          row: i + 2, // Excel行号从2开始（第1行是表头）
          message: error.message || '导入失败',
        });
      }
    }

    this.logger.log(`Students imported: success=${success}, failed=${failed}`);

    return { success, failed, errors };
  }

  async parseStudentImportFile(file: Express.Multer.File): Promise<any[]> {
    const workbook = xlsx.read(file.buffer, { type: 'buffer' });
    const sheetName = workbook.SheetNames[0];
    const sheet = workbook.Sheets[sheetName];
    const data = xlsx.utils.sheet_to_json(sheet, { header: 1 }) as any[][];

    if (data.length < 2) {
      throw new BadRequestException('文件内容为空或格式不正确');
    }

    // 跳过表头，解析数据行
    const students: any[] = [];
    for (let i = 1; i < data.length; i++) {
      const row = data[i];
      if (!row || row.length === 0 || !row[0]) continue; // 跳过空行

      students.push({
        name: String(row[0] || '').trim(),
        gender: String(row[1] || '男').trim(),
        birthDate: row[2] ? this.formatDate(row[2]) : null,
        classId: row[3] ? parseInt(String(row[3]), 10) : null,
        parentName: String(row[4] || '').trim() || null,
        parentPhone: String(row[5] || '').trim() || null,
      });
    }

    if (students.length === 0) {
      throw new BadRequestException('未找到有效的学生数据');
    }

    return students;
  }

  private formatDate(value: any): string | null {
    if (!value) return null;

    // 如果是数字（Excel日期序列号）
    if (typeof value === 'number') {
      const date = xlsx.SSF.parse_date_code(value);
      if (date) {
        return `${date.y}-${String(date.m).padStart(2, '0')}-${String(date.d).padStart(2, '0')}`;
      }
    }

    // 如果是字符串
    const dateStr = String(value).trim();
    const date = new Date(dateStr);
    if (!isNaN(date.getTime())) {
      return date.toISOString().split('T')[0];
    }

    return null;
  }

  // ==================== 班级管理 ====================

  async findClasses(tenantId: number) {
    const classes = await this.prisma.class.findMany({
      where: {
        tenantId: tenantId,
      },
      orderBy: { createdAt: 'desc' },
      include: {
        teacher: {
          select: {
            id: true,
            name: true,
          },
        },
        classTeachers: {
          include: {
            teacher: {
              select: {
                id: true,
                name: true,
                phone: true,
              },
            },
          },
        },
        _count: {
          select: {
            students: true,
            lessons: true,
          },
        },
      },
    });

    return classes.map((cls) => ({
      id: cls.id,
      name: cls.name,
      grade: cls.grade,
      teacherId: cls.teacherId,
      teacherName: cls.teacher?.name,
      studentCount: cls._count.students,
      lessonCount: cls._count.lessons,
      createdAt: cls.createdAt,
      updatedAt: cls.updatedAt,
      // 新增：教师团队
      teachers: cls.classTeachers.map((ct) => ({
        id: ct.id,
        teacherId: ct.teacher.id,
        teacherName: ct.teacher.name,
        teacherPhone: ct.teacher.phone,
        role: ct.role,
        isPrimary: ct.isPrimary,
      })),
    }));
  }

  async findClass(tenantId: number, id: number) {
    const classEntity = await this.prisma.class.findFirst({
      where: {
        id: id,
        tenantId: tenantId,
      },
      include: {
        teacher: {
          select: {
            id: true,
            name: true,
          },
        },
        students: {
          select: {
            id: true,
            name: true,
            gender: true,
            birthDate: true,
            parentName: true,
            parentPhone: true,
            lessonCount: true,
          },
        },
      },
    });

    if (!classEntity) {
      throw new NotFoundException('班级不存在');
    }

    return {
      id: classEntity.id,
      name: classEntity.name,
      grade: classEntity.grade,
      teacherId: classEntity.teacherId,
      teacherName: classEntity.teacher?.name,
      studentCount: classEntity.students.length,
      lessonCount: classEntity.lessonCount,
      students: classEntity.students,
      createdAt: classEntity.createdAt,
      updatedAt: classEntity.updatedAt,
    };
  }

  async findClassStudents(tenantId: number, classId: number, query: any) {
    const { page = 1, pageSize = 20, keyword } = query;

    const skip = (page - 1) * pageSize;
    const take = +pageSize;

    // 验证班级是否存在
    const classEntity = await this.prisma.class.findFirst({
      where: {
        id: classId,
        tenantId: tenantId,
      },
    });

    if (!classEntity) {
      throw new NotFoundException('班级不存在');
    }

    const where: any = {
      classId: classId,
      tenantId: tenantId,
    };

    if (keyword) {
      where.OR = [
        { name: { contains: keyword } },
        { parentName: { contains: keyword } },
      ];
    }

    const [items, total] = await Promise.all([
      this.prisma.student.findMany({
        where,
        skip,
        take,
        orderBy: { createdAt: 'desc' },
      }),
      this.prisma.student.count({ where }),
    ]);

    return {
      items,
      total,
      page: +page,
      pageSize: +pageSize,
    };
  }

  async createClass(tenantId: number, dto: CreateClassDto) {
    // 如果指定了教师，验证教师是否存在
    if (dto.teacherId) {
      const teacher = await this.prisma.teacher.findFirst({
        where: {
          id: dto.teacherId,
          tenantId: tenantId,
        },
      });

      if (!teacher) {
        throw new NotFoundException('教师不存在');
      }
    }

    const classEntity = await this.prisma.class.create({
      data: {
        tenantId: tenantId,
        name: dto.name,
        grade: dto.grade,
        teacherId: dto.teacherId || null,
      },
      include: {
        teacher: {
          select: {
            id: true,
            name: true,
          },
        },
      },
    });

    this.logger.log(`Class created: ${classEntity.id} by tenant ${tenantId}`);

    return {
      id: classEntity.id,
      name: classEntity.name,
      grade: classEntity.grade,
      teacherId: classEntity.teacherId,
      teacherName: classEntity.teacher?.name,
      studentCount: 0,
      lessonCount: 0,
    };
  }

  async updateClass(tenantId: number, id: number, dto: UpdateClassDto) {
    // 检查班级是否存在
    const existingClass = await this.prisma.class.findFirst({
      where: {
        id: id,
        tenantId: tenantId,
      },
    });

    if (!existingClass) {
      throw new NotFoundException('班级不存在');
    }

    // 如果要更换教师，验证教师是否存在
    if (dto.teacherId !== undefined && dto.teacherId !== null) {
      const teacher = await this.prisma.teacher.findFirst({
        where: {
          id: dto.teacherId,
          tenantId: tenantId,
        },
      });

      if (!teacher) {
        throw new NotFoundException('教师不存在');
      }
    }

    const classEntity = await this.prisma.class.update({
      where: { id: id },
      data: {
        name: dto.name,
        grade: dto.grade,
        teacherId: dto.teacherId,
      },
      include: {
        teacher: {
          select: {
            id: true,
            name: true,
          },
        },
        _count: {
          select: {
            students: true,
            lessons: true,
          },
        },
      },
    });

    this.logger.log(`Class updated: ${id}`);

    return {
      id: classEntity.id,
      name: classEntity.name,
      grade: classEntity.grade,
      teacherId: classEntity.teacherId,
      teacherName: classEntity.teacher?.name,
      studentCount: classEntity._count.students,
      lessonCount: classEntity._count.lessons,
    };
  }

  async deleteClass(tenantId: number, id: number) {
    // 检查班级是否存在
    const classEntity = await this.prisma.class.findFirst({
      where: {
        id: id,
        tenantId: tenantId,
      },
      include: {
        _count: {
          select: {
            students: true,
          },
        },
      },
    });

    if (!classEntity) {
      throw new NotFoundException('班级不存在');
    }

    // 检查是否还有学生
    if (classEntity._count.students > 0) {
      throw new ForbiddenException('班级内还有学生，请先移除学生');
    }

    // 删除班级
    await this.prisma.class.delete({
      where: { id: id },
    });

    this.logger.log(`Class deleted: ${id}`);

    return { message: '删除成功' };
  }

  // ==================== 家长管理 ====================

  async findParents(tenantId: number, query: any) {
    const { page = 1, pageSize = 10, keyword, status } = query;

    const skip = (page - 1) * pageSize;
    const take = +pageSize;

    const where: any = {
      tenantId: tenantId,
    };

    if (keyword) {
      where.OR = [
        { name: { contains: keyword } },
        { phone: { contains: keyword } },
        { loginAccount: { contains: keyword } },
      ];
    }

    if (status) {
      where.status = status;
    }

    const [items, total] = await Promise.all([
      this.prisma.parent.findMany({
        where,
        skip,
        take,
        orderBy: { createdAt: 'desc' },
        include: {
          children: {
            include: {
              student: {
                select: {
                  id: true,
                  name: true,
                  class: {
                    select: {
                      id: true,
                      name: true,
                    },
                  },
                },
              },
            },
          },
        },
      }),
      this.prisma.parent.count({ where }),
    ]);

    return {
      items: items.map((parent) => ({
        ...parent,
        childrenCount: parent.children.length,
        children: parent.children.map((c) => ({
          ...c.student,
          relationship: c.relationship,
        })),
      })),
      total,
      page: +page,
      pageSize: +pageSize,
    };
  }

  async findParent(tenantId: number, id: number) {
    const parent = await this.prisma.parent.findFirst({
      where: {
        id: id,
        tenantId: tenantId,
      },
      include: {
        children: {
          include: {
            student: {
              select: {
                id: true,
                name: true,
                gender: true,
                class: {
                  select: {
                    id: true,
                    name: true,
                  },
                },
              },
            },
          },
        },
      },
    });

    if (!parent) {
      throw new NotFoundException('家长不存在');
    }

    return {
      ...parent,
      children: parent.children.map((c) => ({
        ...c.student,
        relationship: c.relationship,
      })),
    };
  }

  async createParent(
    tenantId: number,
    dto: {
      name: string;
      phone: string;
      email?: string;
      loginAccount: string;
      password: string;
    },
  ) {
    // 检查账号是否已存在
    const existing = await this.prisma.parent.findUnique({
      where: { loginAccount: dto.loginAccount },
    });

    if (existing) {
      throw new ForbiddenException('登录账号已存在');
    }

    // 创建家长
    const hashedPassword = await bcrypt.hash(dto.password, 10);

    const parent = await this.prisma.parent.create({
      data: {
        tenantId: tenantId,
        name: dto.name,
        phone: dto.phone,
        email: dto.email,
        loginAccount: dto.loginAccount,
        passwordHash: hashedPassword,
        status: 'ACTIVE',
      },
    });

    this.logger.log(`Parent created: ${parent.id}`);

    return parent;
  }

  async updateParent(
    tenantId: number,
    id: number,
    dto: {
      name?: string;
      phone?: string;
      email?: string;
      status?: string;
      password?: string;
    },
  ) {
    const parent = await this.prisma.parent.findFirst({
      where: { id, tenantId },
    });

    if (!parent) {
      throw new NotFoundException('家长不存在');
    }

    const updateData: any = {
      name: dto.name,
      phone: dto.phone,
      email: dto.email,
      status: dto.status,
    };

    if (dto.password) {
      updateData.passwordHash = await bcrypt.hash(dto.password, 10);
    }

    const updated = await this.prisma.parent.update({
      where: { id },
      data: updateData,
    });

    this.logger.log(`Parent updated: ${id}`);

    return updated;
  }

  async deleteParent(tenantId: number, id: number) {
    const parent = await this.prisma.parent.findFirst({
      where: { id, tenantId },
    });

    if (!parent) {
      throw new NotFoundException('家长不存在');
    }

    await this.prisma.parent.delete({
      where: { id },
    });

    this.logger.log(`Parent deleted: ${id}`);

    return { message: '删除成功' };
  }

  async resetParentPassword(tenantId: number, id: number) {
    const parent = await this.prisma.parent.findFirst({
      where: { id, tenantId },
    });

    if (!parent) {
      throw new NotFoundException('家长不存在');
    }

    // 生成临时密码
    const tempPassword = Math.random().toString(36).slice(-8);
    const hashedPassword = await bcrypt.hash(tempPassword, 10);

    await this.prisma.parent.update({
      where: { id },
      data: { passwordHash: hashedPassword },
    });

    this.logger.log(`Parent password reset: ${id}`);

    return { tempPassword };
  }

  async addChildToParent(
    tenantId: number,
    parentId: number,
    studentId: number,
    relationship: string,
  ) {
    // 验证家长和学生都属于该租户
    const parent = await this.prisma.parent.findFirst({
      where: { id: parentId, tenantId },
    });

    if (!parent) {
      throw new NotFoundException('家长不存在');
    }

    const student = await this.prisma.student.findFirst({
      where: { id: studentId, tenantId },
    });

    if (!student) {
      throw new NotFoundException('学生不存在');
    }

    // 检查是否已关联
    const existing = await this.prisma.parentStudent.findUnique({
      where: {
        parentId_studentId: {
          parentId,
          studentId,
        },
      },
    });

    if (existing) {
      throw new ForbiddenException('该学生已与此家长关联');
    }

    const relation = await this.prisma.parentStudent.create({
      data: {
        parentId,
        studentId,
        relationship,
      },
      include: {
        student: {
          select: {
            id: true,
            name: true,
          },
        },
      },
    });

    this.logger.log(`Child ${studentId} added to parent ${parentId}`);

    return relation;
  }

  async removeChildFromParent(
    tenantId: number,
    parentId: number,
    studentId: number,
  ) {
    // 验证家长属于该租户
    const parent = await this.prisma.parent.findFirst({
      where: { id: parentId, tenantId },
    });

    if (!parent) {
      throw new NotFoundException('家长不存在');
    }

    await this.prisma.parentStudent.delete({
      where: {
        parentId_studentId: {
          parentId,
          studentId,
        },
      },
    });

    this.logger.log(`Child ${studentId} removed from parent ${parentId}`);

    return { message: '解除关联成功' };
  }

  // ==================== 课程管理 ====================

  async findCourses(tenantId: number) {
    // 获取学校已授权的课程列表
    const tenantCourses = await this.prisma.tenantCourse.findMany({
      where: {
        tenantId,
        authorized: true,
      },
      include: {
        course: {
          select: {
            id: true,
            name: true,
            pictureBookName: true,
            coverImagePath: true,
            gradeTags: true,
            domainTags: true,
            duration: true,
            usageCount: true,
            status: true,
          },
        },
      },
    });

    return tenantCourses.map((tc) => ({
      id: tc.course.id,
      name: tc.course.name,
      pictureBookName: tc.course.pictureBookName,
      pictureUrl: tc.course.coverImagePath,
      gradeTags: this.parseJsonArray(tc.course.gradeTags),
      domainTags: this.parseJsonArray(tc.course.domainTags),
      duration: tc.course.duration || 25,
      usageCount: tc.course.usageCount || 0,
      authorized: tc.authorized,
    }));
  }

  async findCourse(tenantId: number, courseId: number) {
    // 检查课程是否存在且已发布
    const course = await this.prisma.course.findUnique({
      where: { id: courseId },
      include: {
        theme: {
          select: { id: true, name: true },
        },
        courseLessons: {
          orderBy: { createdAt: 'asc' },
          include: {
            steps: {
              orderBy: { sortOrder: 'asc' },
            },
          },
        },
        tenantCourses: {
          where: { tenantId },
        },
      },
    });

    if (!course) {
      throw new NotFoundException(`课程 #${courseId} 不存在`);
    }

    if (course.status !== 'PUBLISHED') {
      throw new ForbiddenException('该课程未发布');
    }

    // 检查授权
    const tenantCourse = course.tenantCourses.find((tc) => tc.tenantId === tenantId);
    if (!tenantCourse || !tenantCourse.authorized) {
      throw new ForbiddenException('您的学校未获得此课程的授权');
    }

    // 获取使用该课程的教师数量
    const teacherCount = await this.prisma.lesson.groupBy({
      by: ['teacherId'],
      where: {
        courseId,
        tenantId,
      },
    });

    // 解析 JSON 字段
    return {
      ...course,
      authorized: true, // 既然通过了授权检查，就是已授权的
      gradeTags: JSON.parse(course.gradeTags || '[]'),
      domainTags: JSON.parse(course.domainTags || '[]'),
      scheduleRefData: course.scheduleRefData ? JSON.parse(course.scheduleRefData) : null,
      ebookPaths: course.ebookPaths ? JSON.parse(course.ebookPaths) : null,
      audioPaths: course.audioPaths ? JSON.parse(course.audioPaths) : null,
      videoPaths: course.videoPaths ? JSON.parse(course.videoPaths) : null,
      otherResources: course.otherResources ? JSON.parse(course.otherResources) : null,
      posterPaths: course.posterPaths ? JSON.parse(course.posterPaths) : null,
      tenantCourses: undefined, // 移除敏感信息
      teacherCount: teacherCount.length,
      courseLessons: course.courseLessons.map((lesson) => ({
        ...lesson,
        steps: lesson.steps ? lesson.steps.map((step) => ({
          ...step,
          content: step.content,
        })) : [],
      })),
    };
  }

  // ==================== 班级教师管理 ====================

  async findClassTeachers(tenantId: number, classId: number) {
    // 验证班级存在
    const classEntity = await this.prisma.class.findFirst({
      where: { id: classId, tenantId },
    });

    if (!classEntity) {
      throw new NotFoundException('班级不存在');
    }

    const classTeachers = await this.prisma.classTeacher.findMany({
      where: { classId },
      include: {
        teacher: {
          select: {
            id: true,
            name: true,
            phone: true,
            email: true,
          },
        },
      },
      orderBy: [
        { isPrimary: 'desc' },
        { createdAt: 'asc' },
      ],
    });

    return classTeachers.map((ct) => ({
      id: ct.id,
      teacherId: ct.teacher.id,
      teacherName: ct.teacher.name,
      teacherPhone: ct.teacher.phone,
      teacherEmail: ct.teacher.email,
      role: ct.role,
      isPrimary: ct.isPrimary,
      createdAt: ct.createdAt,
    }));
  }

  async addClassTeacher(tenantId: number, classId: number, dto: AddClassTeacherDto) {
    // 验证班级存在
    const classEntity = await this.prisma.class.findFirst({
      where: { id: classId, tenantId },
    });

    if (!classEntity) {
      throw new NotFoundException('班级不存在');
    }

    // 验证教师存在且属于同一租户
    const teacher = await this.prisma.teacher.findFirst({
      where: { id: dto.teacherId, tenantId },
    });

    if (!teacher) {
      throw new NotFoundException('教师不存在');
    }

    // 检查是否已存在关联
    const existing = await this.prisma.classTeacher.findUnique({
      where: {
        classId_teacherId: { classId, teacherId: dto.teacherId },
      },
    });

    if (existing) {
      throw new ConflictException('该教师已在此班级中');
    }

    // 如果设为班主任，先取消其他班主任
    if (dto.isPrimary) {
      await this.prisma.classTeacher.updateMany({
        where: { classId, isPrimary: true },
        data: { isPrimary: false },
      });
    }

    const classTeacher = await this.prisma.classTeacher.create({
      data: {
        classId,
        teacherId: dto.teacherId,
        role: dto.role,
        isPrimary: dto.isPrimary || false,
      },
      include: {
        teacher: {
          select: {
            id: true,
            name: true,
            phone: true,
          },
        },
      },
    });

    // 如果是主班教师，更新 Class.teacherId（向后兼容）
    if (dto.role === 'MAIN' || dto.isPrimary) {
      await this.prisma.class.update({
        where: { id: classId },
        data: { teacherId: dto.teacherId },
      });
    }

    this.logger.log(`Teacher ${dto.teacherId} added to class ${classId} as ${dto.role}`);

    return {
      id: classTeacher.id,
      teacherId: classTeacher.teacher.id,
      teacherName: classTeacher.teacher.name,
      teacherPhone: classTeacher.teacher.phone,
      role: classTeacher.role,
      isPrimary: classTeacher.isPrimary,
    };
  }

  async updateClassTeacher(
    tenantId: number,
    classId: number,
    teacherId: number,
    dto: UpdateClassTeacherDto,
  ) {
    // 验证班级存在
    const classEntity = await this.prisma.class.findFirst({
      where: { id: classId, tenantId },
    });

    if (!classEntity) {
      throw new NotFoundException('班级不存在');
    }

    // 查找关联记录
    const classTeacher = await this.prisma.classTeacher.findUnique({
      where: {
        classId_teacherId: { classId, teacherId },
      },
    });

    if (!classTeacher) {
      throw new NotFoundException('该教师不在此班级中');
    }

    // 如果设为班主任，先取消其他班主任
    if (dto.isPrimary) {
      await this.prisma.classTeacher.updateMany({
        where: { classId, isPrimary: true },
        data: { isPrimary: false },
      });
    }

    const updated = await this.prisma.classTeacher.update({
      where: {
        classId_teacherId: { classId, teacherId },
      },
      data: {
        role: dto.role,
        isPrimary: dto.isPrimary,
      },
      include: {
        teacher: {
          select: {
            id: true,
            name: true,
            phone: true,
          },
        },
      },
    });

    // 如果是主班教师，更新 Class.teacherId（向后兼容）
    if (dto.role === 'MAIN' || dto.isPrimary) {
      await this.prisma.class.update({
        where: { id: classId },
        data: { teacherId },
      });
    }

    this.logger.log(`Teacher ${teacherId} updated in class ${classId}`);

    return {
      id: updated.id,
      teacherId: updated.teacher.id,
      teacherName: updated.teacher.name,
      teacherPhone: updated.teacher.phone,
      role: updated.role,
      isPrimary: updated.isPrimary,
    };
  }

  async removeClassTeacher(tenantId: number, classId: number, teacherId: number) {
    // 验证班级存在
    const classEntity = await this.prisma.class.findFirst({
      where: { id: classId, tenantId },
    });

    if (!classEntity) {
      throw new NotFoundException('班级不存在');
    }

    // 查找关联记录
    const classTeacher = await this.prisma.classTeacher.findUnique({
      where: {
        classId_teacherId: { classId, teacherId },
      },
    });

    if (!classTeacher) {
      throw new NotFoundException('该教师不在此班级中');
    }

    await this.prisma.classTeacher.delete({
      where: {
        classId_teacherId: { classId, teacherId },
      },
    });

    // 如果移除的是当前班主任，清空 Class.teacherId
    if (classEntity.teacherId === teacherId) {
      // 查找是否还有其他主班教师
      const nextMainTeacher = await this.prisma.classTeacher.findFirst({
        where: { classId, role: 'MAIN' },
        orderBy: { createdAt: 'asc' },
      });

      await this.prisma.class.update({
        where: { id: classId },
        data: { teacherId: nextMainTeacher?.teacherId || null },
      });
    }

    this.logger.log(`Teacher ${teacherId} removed from class ${classId}`);

    return { message: '移除成功' };
  }

  // ==================== 学生调班 ====================

  async transferStudent(tenantId: number, studentId: number, dto: TransferStudentDto) {
    // 查找学生
    const student = await this.prisma.student.findFirst({
      where: { id: studentId, tenantId },
    });

    if (!student) {
      throw new NotFoundException('学生不存在');
    }

    // 验证目标班级存在
    const toClass = await this.prisma.class.findFirst({
      where: { id: dto.toClassId, tenantId },
    });

    if (!toClass) {
      throw new NotFoundException('目标班级不存在');
    }

    // 如果是同一个班级，不做处理
    if (student.classId === dto.toClassId) {
      throw new BadRequestException('学生已在此班级中');
    }

    const fromClassId = student.classId;

    // 使用事务处理
    await this.prisma.$transaction(async (tx) => {
      // 更新学生班级
      await tx.student.update({
        where: { id: studentId },
        data: { classId: dto.toClassId },
      });

      // 更新原班级学生数量
      await tx.class.update({
        where: { id: fromClassId },
        data: { studentCount: { decrement: 1 } },
      });

      // 更新新班级学生数量
      await tx.class.update({
        where: { id: dto.toClassId },
        data: { studentCount: { increment: 1 } },
      });

      // 记录调班历史
      await tx.studentClassHistory.create({
        data: {
          studentId,
          fromClassId,
          toClassId: dto.toClassId,
          reason: dto.reason,
          operatedBy: null, // TODO: 从请求中获取操作人ID
        },
      });
    });

    this.logger.log(`Student ${studentId} transferred from class ${fromClassId} to ${dto.toClassId}`);

    return { message: '调班成功' };
  }

  async getStudentClassHistory(tenantId: number, studentId: number) {
    // 验证学生存在
    const student = await this.prisma.student.findFirst({
      where: { id: studentId, tenantId },
    });

    if (!student) {
      throw new NotFoundException('学生不存在');
    }

    const history = await this.prisma.studentClassHistory.findMany({
      where: { studentId },
      include: {
        fromClass: {
          select: { id: true, name: true, grade: true },
        },
        toClass: {
          select: { id: true, name: true, grade: true },
        },
      },
      orderBy: { createdAt: 'desc' },
    });

    return history.map((h) => ({
      id: h.id,
      fromClass: h.fromClass ? { id: h.fromClass.id, name: h.fromClass.name, grade: h.fromClass.grade } : null,
      toClass: { id: h.toClass.id, name: h.toClass.name, grade: h.toClass.grade },
      reason: h.reason,
      operatedBy: h.operatedBy,
      createdAt: h.createdAt,
    }));
  }

  // ==================== 排课管理 ====================

  /**
   * 解析时间字符串为分钟数
   * @param timeStr 格式: "HH:mm"
   * @returns 从午夜开始的分钟数
   */
  private parseTimeToMinutes(timeStr: string): number {
    const [hours, minutes] = timeStr.split(':').map(Number);
    return hours * 60 + minutes;
  }

  /**
   * 检查两个时间段是否重叠
   * @param time1 格式: "HH:mm-HH:mm"
   * @param time2 格式: "HH:mm-HH:mm"
   */
  private isTimeOverlapping(time1: string, time2: string): boolean {
    const [start1, end1] = time1.split('-').map(t => this.parseTimeToMinutes(t.trim()));
    const [start2, end2] = time2.split('-').map(t => this.parseTimeToMinutes(t.trim()));

    // 两个时间段重叠的条件: start1 < end2 AND start2 < end1
    return start1 < end2 && start2 < end1;
  }

  /**
   * 检查教师排课时间冲突
   * @param teacherId 教师ID
   * @param scheduledDate 排课日期
   * @param scheduledTime 时间段
   * @param excludeScheduleId 排除的排课ID（用于更新时排除自身）
   * @returns 如果有冲突返回冲突的排课信息，否则返回null
   */
  private async checkScheduleConflict(
    teacherId: number,
    scheduledDate: string,
    scheduledTime: string,
    excludeScheduleId?: number,
  ): Promise<{ courseName: string; className: string; scheduledTime: string } | null> {
    // 使用日期范围查询，避免时区问题
    const dateStart = new Date(scheduledDate + 'T00:00:00.000Z');
    const dateEnd = new Date(scheduledDate + 'T23:59:59.999Z');

    // 获取该教师当天的所有排课
    const existingSchedules = await this.prisma.schedulePlan.findMany({
      where: {
        teacherId,
        scheduledDate: {
          gte: dateStart,
          lte: dateEnd,
        },
        status: 'ACTIVE',
        ...(excludeScheduleId && { id: { not: excludeScheduleId } }),
      },
      include: {
        class: { select: { name: true } },
        course: { select: { name: true } },
      },
    });

    // 检查是否存在时间重叠
    for (const schedule of existingSchedules) {
      if (schedule.scheduledTime && this.isTimeOverlapping(scheduledTime, schedule.scheduledTime)) {
        return {
          courseName: schedule.course.name,
          className: schedule.class.name,
          scheduledTime: schedule.scheduledTime,
        };
      }
    }

    return null;
  }

  async findSchedules(tenantId: number, query: QueryScheduleDto) {
    const { page = 1, pageSize = 20, classId, teacherId, courseId, startDate, endDate, status, source } = query;

    const skip = (page - 1) * pageSize;
    const take = +pageSize;

    const where: any = {
      tenantId,
    };

    if (classId) where.classId = classId;
    if (teacherId) where.teacherId = teacherId;
    if (courseId) where.courseId = courseId;
    if (status) where.status = status;
    if (source) where.source = source;

    if (startDate || endDate) {
      where.scheduledDate = {};
      if (startDate) where.scheduledDate.gte = new Date(startDate);
      if (endDate) where.scheduledDate.lte = new Date(endDate);
    }

    const [items, total] = await Promise.all([
      this.prisma.schedulePlan.findMany({
        where,
        skip,
        take,
        orderBy: { scheduledDate: 'asc' },
        include: {
          class: { select: { id: true, name: true, grade: true } },
          course: { select: { id: true, name: true, pictureBookName: true, duration: true } },
          teacher: { select: { id: true, name: true, phone: true } },
        },
      }),
      this.prisma.schedulePlan.count({ where }),
    ]);

    return {
      items: items.map((item) => ({
        ...item,
        className: item.class.name,
        courseName: item.course.name,
        teacherName: item.teacher?.name,
      })),
      total,
      page: +page,
      pageSize: +pageSize,
    };
  }

  async findSchedule(tenantId: number, id: number) {
    const schedule = await this.prisma.schedulePlan.findFirst({
      where: { id, tenantId },
      include: {
        class: { select: { id: true, name: true, grade: true } },
        course: { select: { id: true, name: true, pictureBookName: true, duration: true } },
        teacher: { select: { id: true, name: true, phone: true } },
      },
    });

    if (!schedule) {
      throw new NotFoundException('排课计划不存在');
    }

    return {
      ...schedule,
      className: schedule.class.name,
      courseName: schedule.course.name,
      teacherName: schedule.teacher?.name,
    };
  }

  async createSchedule(tenantId: number, dto: CreateScheduleDto, userId: number) {
    // 验证班级存在
    const classEntity = await this.prisma.class.findFirst({
      where: { id: dto.classId, tenantId },
    });
    if (!classEntity) {
      throw new NotFoundException('班级不存在');
    }

    // 验证课程存在且已授权
    const tenantCourse = await this.prisma.tenantCourse.findFirst({
      where: { tenantId, courseId: dto.courseId, authorized: true },
    });
    if (!tenantCourse) {
      throw new ForbiddenException('该课程未授权或不存在');
    }

    // 如果指定了教师，验证教师存在
    if (dto.teacherId) {
      const teacher = await this.prisma.teacher.findFirst({
        where: { id: dto.teacherId, tenantId },
      });
      if (!teacher) {
        throw new NotFoundException('教师不存在');
      }

      // 检查教师时间冲突
      if (dto.scheduledDate && dto.scheduledTime) {
        const conflict = await this.checkScheduleConflict(dto.teacherId, dto.scheduledDate, dto.scheduledTime);
        if (conflict) {
          throw new ConflictException(
            `时间冲突：该教师在 ${conflict.scheduledTime} 已有排课「${conflict.courseName}」（${conflict.className}），请选择其他时间段`
          );
        }
      }
    }

    const schedule = await this.prisma.schedulePlan.create({
      data: {
        tenantId,
        classId: dto.classId,
        courseId: dto.courseId,
        teacherId: dto.teacherId,
        scheduledDate: dto.scheduledDate ? new Date(dto.scheduledDate) : null,
        scheduledTime: dto.scheduledTime,
        weekDay: dto.weekDay,
        repeatType: dto.repeatType,
        repeatEndDate: dto.repeatEndDate ? new Date(dto.repeatEndDate) : null,
        source: 'SCHOOL',
        createdBy: userId,
        note: dto.note,
        status: 'ACTIVE',
      },
      include: {
        class: { select: { id: true, name: true } },
        course: { select: { id: true, name: true } },
        teacher: { select: { id: true, name: true } },
      },
    });

    this.logger.log(`Schedule created: ${schedule.id} by user ${userId}`);

    return {
      ...schedule,
      className: schedule.class.name,
      courseName: schedule.course.name,
      teacherName: schedule.teacher?.name,
    };
  }

  async updateSchedule(tenantId: number, id: number, dto: UpdateScheduleDto) {
    const schedule = await this.prisma.schedulePlan.findFirst({
      where: { id, tenantId },
    });

    if (!schedule) {
      throw new NotFoundException('排课计划不存在');
    }

    // 如果更新教师，验证教师存在
    if (dto.teacherId !== undefined) {
      if (dto.teacherId) {
        const teacher = await this.prisma.teacher.findFirst({
          where: { id: dto.teacherId, tenantId },
        });
        if (!teacher) {
          throw new NotFoundException('教师不存在');
        }
      }
    }

    const updated = await this.prisma.schedulePlan.update({
      where: { id },
      data: {
        teacherId: dto.teacherId,
        scheduledDate: dto.scheduledDate ? new Date(dto.scheduledDate) : undefined,
        scheduledTime: dto.scheduledTime,
        weekDay: dto.weekDay,
        repeatType: dto.repeatType,
        repeatEndDate: dto.repeatEndDate ? new Date(dto.repeatEndDate) : undefined,
        note: dto.note,
        status: dto.status,
      },
      include: {
        class: { select: { id: true, name: true } },
        course: { select: { id: true, name: true } },
        teacher: { select: { id: true, name: true } },
      },
    });

    this.logger.log(`Schedule updated: ${id}`);

    return {
      ...updated,
      className: updated.class.name,
      courseName: updated.course.name,
      teacherName: updated.teacher?.name,
    };
  }

  async cancelSchedule(tenantId: number, id: number) {
    const schedule = await this.prisma.schedulePlan.findFirst({
      where: { id, tenantId },
    });

    if (!schedule) {
      throw new NotFoundException('排课计划不存在');
    }

    await this.prisma.schedulePlan.update({
      where: { id },
      data: { status: 'CANCELLED' },
    });

    this.logger.log(`Schedule cancelled: ${id}`);

    return { message: '取消成功' };
  }

  async getTimetable(tenantId: number, query: TimetableQueryDto) {
    const { startDate, endDate, classId, teacherId } = query;

    const where: any = {
      tenantId,
      status: 'ACTIVE',
      scheduledDate: {
        gte: new Date(startDate),
        lte: new Date(endDate),
      },
    };

    if (classId) where.classId = classId;
    if (teacherId) where.teacherId = teacherId;

    const schedules = await this.prisma.schedulePlan.findMany({
      where,
      orderBy: [{ scheduledDate: 'asc' }, { scheduledTime: 'asc' }],
      include: {
        class: { select: { id: true, name: true, grade: true } },
        course: { select: { id: true, name: true, pictureBookName: true, duration: true } },
        teacher: { select: { id: true, name: true } },
      },
    });

    // 按日期分组
    const timetable: Record<string, any[]> = {};
    const start = new Date(startDate);
    const end = new Date(endDate);

    // 初始化所有日期
    for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
      const dateStr = d.toISOString().split('T')[0];
      timetable[dateStr] = [];
    }

    // 填充排课数据
    schedules.forEach((schedule) => {
      const dateStr = schedule.scheduledDate!.toISOString().split('T')[0];
      if (timetable[dateStr]) {
        timetable[dateStr].push({
          ...schedule,
          className: schedule.class.name,
          courseName: schedule.course.name,
          teacherName: schedule.teacher?.name,
        });
      }
    });

    return Object.entries(timetable).map(([date, items]) => ({
      date,
      weekDay: new Date(date).getDay(),
      schedules: items,
    }));
  }

  // ==================== 批量排课 ====================

  async batchCreateSchedules(tenantId: number, schedules: Array<{
    classId: number;
    courseId: number;
    teacherId?: number;
    scheduledDate: string;
    scheduledTime?: string;
    note?: string;
  }>) {
    const results = [];
    const errors = [];

    for (let i = 0; i < schedules.length; i++) {
      const item = schedules[i];
      try {
        // 验证班级存在
        const classEntity = await this.prisma.class.findFirst({
          where: { id: item.classId, tenantId },
        });

        if (!classEntity) {
          errors.push({ index: i, message: '班级不存在或无权限' });
          continue;
        }

        // 验证课程存在且已授权
        const tenantCourse = await this.prisma.tenantCourse.findFirst({
          where: { tenantId, courseId: item.courseId, authorized: true },
        });

        if (!tenantCourse) {
          errors.push({ index: i, message: '课程未授权或不存在' });
          continue;
        }

        // 如果指定了教师，验证教师存在
        if (item.teacherId) {
          const teacher = await this.prisma.teacher.findFirst({
            where: { id: item.teacherId, tenantId },
          });

          if (!teacher) {
            errors.push({ index: i, message: '教师不存在' });
            continue;
          }
        }

        // 创建排课
        const schedule = await this.prisma.schedulePlan.create({
          data: {
            tenantId,
            classId: item.classId,
            courseId: item.courseId,
            teacherId: item.teacherId,
            scheduledDate: new Date(item.scheduledDate),
            scheduledTime: item.scheduledTime,
            repeatType: 'NONE',
            source: 'SCHOOL',
            createdBy: 0, // 批量创建
            status: 'ACTIVE',
            note: item.note,
          },
          include: {
            class: { select: { id: true, name: true } },
            course: { select: { id: true, name: true } },
            teacher: { select: { id: true, name: true } },
          },
        });

        results.push({
          ...schedule,
          className: schedule.class.name,
          courseName: schedule.course.name,
          teacherName: schedule.teacher?.name,
        });
      } catch (error) {
        errors.push({ index: i, message: error.message || '创建失败' });
      }
    }

    this.logger.log(
      `Batch create schedules: ${results.length} success, ${errors.length} failed`
    );

    return {
      success: results.length,
      failed: errors.length,
      results,
      errors,
    };
  }

  // ==================== 排课模板 ====================

  async getScheduleTemplates(tenantId: number, query?: { classId?: number; courseId?: number }) {
    const where: any = { tenantId };

    if (query?.classId) {
      where.classId = query.classId;
    }

    if (query?.courseId) {
      where.courseId = query.courseId;
    }

    const templates = await this.prisma.scheduleTemplate.findMany({
      where,
      orderBy: [
        { isDefault: 'desc' },
        { createdAt: 'desc' },
      ],
      include: {
        course: {
          select: { id: true, name: true, pictureBookName: true },
        },
        class: {
          select: { id: true, name: true, grade: true },
        },
        teacher: {
          select: { id: true, name: true },
        },
      },
    });

    return templates.map((t) => ({
      ...t,
      courseName: t.course?.name,
      className: t.class?.name,
      teacherName: t.teacher?.name,
    }));
  }

  async getScheduleTemplate(tenantId: number, id: number) {
    const template = await this.prisma.scheduleTemplate.findFirst({
      where: { id, tenantId },
      include: {
        course: {
          select: { id: true, name: true, pictureBookName: true, duration: true },
        },
        class: {
          select: { id: true, name: true, grade: true },
        },
        teacher: {
          select: { id: true, name: true },
        },
      },
    });

    if (!template) {
      throw new NotFoundException('模板不存在');
    }

    return {
      ...template,
      courseName: template.course?.name,
      className: template.class?.name,
      teacherName: template.teacher?.name,
    };
  }

  async createScheduleTemplate(tenantId: number, data: {
    name: string;
    courseId: number;
    classId?: number;
    teacherId?: number;
    scheduledTime?: string;
    weekDay?: number;
    duration?: number;
    isDefault?: boolean;
  }) {
    // 验证课程存在且已授权
    const tenantCourse = await this.prisma.tenantCourse.findFirst({
      where: { tenantId, courseId: data.courseId, authorized: true },
    });

    if (!tenantCourse) {
      throw new BadRequestException('该课程未授权或不存在');
    }

    // 如果设为默认模板，先取消其他默认模板
    if (data.isDefault) {
      await this.prisma.scheduleTemplate.updateMany({
        where: {
          tenantId,
          courseId: data.courseId,
          isDefault: true,
        },
        data: { isDefault: false },
      });
    }

    const template = await this.prisma.scheduleTemplate.create({
      data: {
        tenantId,
        name: data.name,
        courseId: data.courseId,
        classId: data.classId,
        teacherId: data.teacherId,
        scheduledTime: data.scheduledTime,
        weekDay: data.weekDay,
        duration: data.duration || 25,
        isDefault: data.isDefault || false,
      },
      include: {
        course: { select: { id: true, name: true } },
        class: { select: { id: true, name: true } },
        teacher: { select: { id: true, name: true } },
      },
    });

    this.logger.log(`Schedule template created: ${template.id}`);

    return {
      ...template,
      courseName: template.course?.name,
      className: template.class?.name,
      teacherName: template.teacher?.name,
    };
  }

  async updateScheduleTemplate(tenantId: number, id: number, data: {
    name?: string;
    classId?: number;
    teacherId?: number;
    scheduledTime?: string;
    weekDay?: number;
    duration?: number;
    isDefault?: boolean;
  }) {
    const template = await this.prisma.scheduleTemplate.findFirst({
      where: { id, tenantId },
    });

    if (!template) {
      throw new NotFoundException('模板不存在');
    }

    // 如果设为默认模板，先取消其他默认模板
    if (data.isDefault) {
      await this.prisma.scheduleTemplate.updateMany({
        where: {
          tenantId,
          courseId: template.courseId,
          isDefault: true,
          id: { not: id },
        },
        data: { isDefault: false },
      });
    }

    const updated = await this.prisma.scheduleTemplate.update({
      where: { id },
      data: {
        name: data.name,
        classId: data.classId,
        teacherId: data.teacherId,
        scheduledTime: data.scheduledTime,
        weekDay: data.weekDay,
        duration: data.duration,
        isDefault: data.isDefault,
      },
      include: {
        course: { select: { id: true, name: true } },
        class: { select: { id: true, name: true } },
        teacher: { select: { id: true, name: true } },
      },
    });

    return {
      ...updated,
      courseName: updated.course?.name,
      className: updated.class?.name,
      teacherName: updated.teacher?.name,
    };
  }

  async deleteScheduleTemplate(tenantId: number, id: number) {
    const template = await this.prisma.scheduleTemplate.findFirst({
      where: { id, tenantId },
    });

    if (!template) {
      throw new NotFoundException('模板不存在');
    }

    await this.prisma.scheduleTemplate.delete({
      where: { id },
    });

    this.logger.log(`Schedule template deleted: ${id}`);

    return { message: '删除成功' };
  }

  async applyScheduleTemplate(tenantId: number, templateId: number, data: {
    scheduledDate: string;
    classId?: number;
    teacherId?: number;
  }) {
    const template = await this.prisma.scheduleTemplate.findFirst({
      where: { id: templateId, tenantId },
    });

    if (!template) {
      throw new NotFoundException('模板不存在');
    }

    // 使用模板创建排课
    const schedule = await this.prisma.schedulePlan.create({
      data: {
        tenantId,
        classId: data.classId || template.classId!,
        courseId: template.courseId,
        teacherId: data.teacherId || template.teacherId,
        scheduledDate: new Date(data.scheduledDate),
        scheduledTime: template.scheduledTime,
        repeatType: 'NONE',
        source: 'SCHOOL',
        createdBy: 0, // 模板创建
        status: 'ACTIVE',
      },
      include: {
        class: { select: { id: true, name: true } },
        course: { select: { id: true, name: true } },
      },
    });

    this.logger.log(`Schedule created from template ${templateId}: ${schedule.id}`);

    return {
      ...schedule,
      className: schedule.class.name,
      courseName: schedule.course.name,
    };
  }
}
