import { Injectable, NotFoundException, ForbiddenException, Logger } from '@nestjs/common';
import { PrismaService } from '../../database/prisma.service';
import { CreateTaskDto, UpdateTaskDto, UpdateCompletionDto, TaskStatus, CompletionStatus, CreateTaskTemplateDto, UpdateTaskTemplateDto } from './dto/create-task.dto';

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

  constructor(private prisma: PrismaService) {}

  // ==================== 任务管理 ====================

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

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

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

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

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

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

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

    return {
      items: items.map((task) => ({
        ...task,
        targetCount: task._count.targets,
        completionCount: task._count.completions,
        _count: undefined,
      })),
      total,
      page: +page,
      pageSize: +pageSize,
    };
  }

  async findOne(tenantId: number, id: number) {
    const task = await this.prisma.task.findFirst({
      where: {
        id: id,
        tenantId: tenantId,
      },
      include: {
        course: {
          select: {
            id: true,
            name: true,
          },
        },
        targets: {
          include: {
            task: {
              select: { id: true, title: true },
            },
          },
        },
        completions: {
          include: {
            student: {
              select: {
                id: true,
                name: true,
              },
            },
          },
        },
      },
    });

    if (!task) {
      throw new NotFoundException('任务不存在');
    }

    return task;
  }

  async create(tenantId: number, userId: number, dto: CreateTaskDto) {
    const task = await this.prisma.task.create({
      data: {
        tenantId: tenantId,
        title: dto.title,
        description: dto.description,
        taskType: dto.taskType,
        targetType: dto.targetType,
        relatedCourseId: dto.relatedCourseId,
        createdBy: userId,
        startDate: new Date(dto.startDate),
        endDate: new Date(dto.endDate),
        status: TaskStatus.PUBLISHED,
      },
    });

    // 创建任务目标
    if (dto.targetIds && dto.targetIds.length > 0) {
      for (const targetId of dto.targetIds) {
        await this.prisma.taskTarget.create({
          data: {
            taskId: task.id,
            classId: dto.targetType === 'CLASS' ? targetId : null,
            studentId: dto.targetType === 'STUDENT' ? targetId : null,
          },
        });

        // 如果是班级，创建所有学生的完成记录
        if (dto.targetType === 'CLASS') {
          const students = await this.prisma.student.findMany({
            where: { classId: targetId, tenantId },
            select: { id: true },
          });
          for (const student of students) {
            await this.prisma.taskCompletion.create({
              data: {
                taskId: task.id,
                studentId: student.id,
                status: CompletionStatus.PENDING,
              },
            });
          }
        } else {
          // 如果是学生，直接创建完成记录
          await this.prisma.taskCompletion.create({
            data: {
              taskId: task.id,
              studentId: targetId,
              status: CompletionStatus.PENDING,
            },
          });
        }
      }
    }

    this.logger.log(`Task created: ${task.id}`);

    return this.findOne(tenantId, task.id);
  }

  async update(tenantId: number, id: number, dto: UpdateTaskDto) {
    const existing = await this.prisma.task.findFirst({
      where: { id, tenantId },
    });

    if (!existing) {
      throw new NotFoundException('任务不存在');
    }

    const task = await this.prisma.task.update({
      where: { id },
      data: {
        title: dto.title,
        description: dto.description,
        startDate: dto.startDate ? new Date(dto.startDate) : undefined,
        endDate: dto.endDate ? new Date(dto.endDate) : undefined,
        status: dto.status,
      },
    });

    // 如果更新了目标
    if (dto.targetIds) {
      // 删除旧目标
      await this.prisma.taskTarget.deleteMany({
        where: { taskId: id },
      });

      // 创建新目标
      for (const targetId of dto.targetIds) {
        await this.prisma.taskTarget.create({
          data: {
            taskId: id,
            classId: existing.targetType === 'CLASS' ? targetId : null,
            studentId: existing.targetType === 'STUDENT' ? targetId : null,
          },
        });
      }
    }

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

    return this.findOne(tenantId, id);
  }

  async delete(tenantId: number, id: number) {
    const existing = await this.prisma.task.findFirst({
      where: { id, tenantId },
    });

    if (!existing) {
      throw new NotFoundException('任务不存在');
    }

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

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

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

  // ==================== 任务完成情况 ====================

  async getCompletions(tenantId: number, taskId: number, query: any) {
    const { page = 1, pageSize = 20, status } = query;

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

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

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

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

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

  async updateCompletion(
    tenantId: number,
    taskId: number,
    studentId: number,
    dto: UpdateCompletionDto,
  ) {
    const completion = await this.prisma.taskCompletion.findFirst({
      where: {
        taskId: taskId,
        studentId: studentId,
        task: { tenantId },
      },
    });

    if (!completion) {
      throw new NotFoundException('任务完成记录不存在');
    }

    const updated = await this.prisma.taskCompletion.update({
      where: {
        taskId_studentId: {
          taskId: taskId,
          studentId: studentId,
        },
      },
      data: {
        status: dto.status,
        completedAt: dto.status === CompletionStatus.COMPLETED ? new Date() : undefined,
        feedback: dto.feedback,
        parentFeedback: dto.parentFeedback,
      },
    });

    this.logger.log(`Task completion updated: task=${taskId}, student=${studentId}`);

    return updated;
  }

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

    const where: any = {
      studentId: studentId,
      task: { tenantId, status: TaskStatus.PUBLISHED },
    };

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

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

    const [items, total] = await Promise.all([
      this.prisma.taskCompletion.findMany({
        where,
        skip,
        take,
        orderBy: { task: { createdAt: 'desc' } },
        include: {
          task: {
            select: {
              id: true,
              title: true,
              taskType: true,
              startDate: true,
              endDate: true,
            },
          },
        },
      }),
      this.prisma.taskCompletion.count({ where }),
    ]);

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

  // ==================== 统计数据 ====================

  async getStats(tenantId: number) {
    const [totalTasks, publishedTasks, completedTasks, inProgressTasks, pendingCount, totalCompletions] = await Promise.all([
      this.prisma.task.count({ where: { tenantId } }),
      this.prisma.task.count({ where: { tenantId, status: TaskStatus.PUBLISHED } }),
      this.prisma.taskCompletion.count({
        where: { task: { tenantId }, status: CompletionStatus.COMPLETED },
      }),
      this.prisma.taskCompletion.count({
        where: { task: { tenantId }, status: CompletionStatus.IN_PROGRESS },
      }),
      this.prisma.taskCompletion.count({
        where: { task: { tenantId }, status: CompletionStatus.PENDING },
      }),
      this.prisma.taskCompletion.count({
        where: { task: { tenantId } },
      }),
    ]);

    const completionRate = totalCompletions > 0
      ? Math.round((completedTasks / totalCompletions) * 100)
      : 0;

    return {
      totalTasks,
      publishedTasks,
      completedTasks,
      inProgressTasks,
      pendingCount,
      totalCompletions,
      completionRate,
    };
  }

  // 按任务类型统计
  async getStatsByType(tenantId: number) {
    const tasks = await this.prisma.task.findMany({
      where: { tenantId },
      select: {
        taskType: true,
        completions: {
          select: { status: true },
        },
      },
    });

    const typeStats: Record<string, { total: number; completed: number; rate: number }> = {};

    for (const task of tasks) {
      if (!typeStats[task.taskType]) {
        typeStats[task.taskType] = { total: 0, completed: 0, rate: 0 };
      }
      typeStats[task.taskType].total += task.completions.length;
      typeStats[task.taskType].completed += task.completions.filter(
        c => c.status === CompletionStatus.COMPLETED
      ).length;
    }

    for (const type of Object.keys(typeStats)) {
      const stat = typeStats[type];
      stat.rate = stat.total > 0 ? Math.round((stat.completed / stat.total) * 100) : 0;
    }

    return typeStats;
  }

  // 按班级统计
  async getStatsByClass(tenantId: number) {
    const classes = await this.prisma.class.findMany({
      where: { tenantId },
      select: {
        id: true,
        name: true,
        grade: true,
      },
    });

    const classStats = await Promise.all(
      classes.map(async (cls) => {
        // 获取班级学生的任务完成记录
        const completions = await this.prisma.taskCompletion.findMany({
          where: {
            student: { classId: cls.id },
            task: { tenantId },
          },
          select: { status: true },
        });

        const total = completions.length;
        const completed = completions.filter(c => c.status === CompletionStatus.COMPLETED).length;
        const rate = total > 0 ? Math.round((completed / total) * 100) : 0;

        return {
          classId: cls.id,
          className: cls.name,
          grade: cls.grade,
          total,
          completed,
          rate,
        };
      })
    );

    return classStats.filter(s => s.total > 0);
  }

  // 按月统计趋势
  async getMonthlyStats(tenantId: number, months: number = 6) {
    const now = new Date();
    const startDate = new Date(now.getFullYear(), now.getMonth() - months + 1, 1);

    const tasks = await this.prisma.task.findMany({
      where: {
        tenantId,
        createdAt: { gte: startDate },
      },
      select: {
        createdAt: true,
        completions: {
          select: { status: true },
        },
      },
    });

    const monthlyData: Record<string, { tasks: number; completions: number; completed: number }> = {};

    // 初始化月份
    for (let i = 0; i < months; i++) {
      const date = new Date(now.getFullYear(), now.getMonth() - i, 1);
      const key = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}`;
      monthlyData[key] = { tasks: 0, completions: 0, completed: 0 };
    }

    // 填充数据
    for (const task of tasks) {
      const key = `${task.createdAt.getFullYear()}-${String(task.createdAt.getMonth() + 1).padStart(2, '0')}`;
      if (monthlyData[key]) {
        monthlyData[key].tasks += 1;
        monthlyData[key].completions += task.completions.length;
        monthlyData[key].completed += task.completions.filter(
          c => c.status === CompletionStatus.COMPLETED
        ).length;
      }
    }

    return Object.entries(monthlyData)
      .sort(([a], [b]) => a.localeCompare(b))
      .map(([month, data]) => ({
        month,
        tasks: data.tasks,
        completions: data.completions,
        completed: data.completed,
        rate: data.completions > 0
          ? Math.round((data.completed / data.completions) * 100)
          : 0,
      }));
  }

  // ==================== 按班级查询 ====================

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

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

    // 查找班级相关的任务（通过 taskTargets）
    const where: any = {
      tenantId,
      targets: {
        some: {
          classId: classId,
        },
      },
    };

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

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

    // 计算完成率
    const itemsWithProgress = await Promise.all(
      items.map(async (task) => {
        const completedCount = await this.prisma.taskCompletion.count({
          where: {
            taskId: task.id,
            status: CompletionStatus.COMPLETED,
          },
        });
        return {
          ...task,
          completionCount: task._count.completions,
          completedCount,
          progress: task._count.completions > 0
            ? Math.round((completedCount / task._count.completions) * 100)
            : 0,
          _count: undefined,
        };
      })
    );

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

  // ==================== 即将到期的任务 ====================

  async getUpcoming(tenantId: number, query: any) {
    const { days = 7, limit = 10 } = query;

    const now = new Date();
    const endDate = new Date();
    endDate.setDate(now.getDate() + Number(days));

    const tasks = await this.prisma.task.findMany({
      where: {
        tenantId,
        status: TaskStatus.PUBLISHED,
        endDate: {
          gte: now,
          lte: endDate,
        },
      },
      take: Number(limit),
      orderBy: { endDate: 'asc' },
      include: {
        course: {
          select: {
            id: true,
            name: true,
          },
        },
        _count: {
          select: {
            completions: {
              where: {
                status: {
                  not: CompletionStatus.COMPLETED,
                },
              },
            },
          },
        },
      },
    });

    return tasks.map((task) => ({
      ...task,
      pendingCount: task._count.completions,
      daysRemaining: Math.ceil((task.endDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24)),
      _count: undefined,
    }));
  }

  // ==================== 发送提醒 ====================

  async sendReminder(tenantId: number, taskId: number) {
    const task = await this.prisma.task.findFirst({
      where: { id: taskId, tenantId },
      include: {
        completions: {
          where: {
            status: {
              not: CompletionStatus.COMPLETED,
            },
          },
          include: {
            student: {
              select: {
                id: true,
                name: true,
                parentPhone: true,
              },
            },
          },
        },
      },
    });

    if (!task) {
      throw new NotFoundException('任务不存在');
    }

    // 这里可以集成短信或推送通知服务
    // 目前只返回需要提醒的学生列表
    const studentsToRemind = task.completions.map((c) => ({
      studentId: c.student.id,
      studentName: c.student.name,
      parentPhone: c.student.parentPhone,
    }));

    this.logger.log(`Reminder sent for task ${taskId} to ${studentsToRemind.length} students`);

    return {
      message: '提醒已发送',
      remindedCount: studentsToRemind.length,
      students: studentsToRemind,
    };
  }

  // ==================== 任务模板 ====================

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

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

    const where: any = {
      tenantId: tenantId,
      status: 'ACTIVE',
    };

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

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

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

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

  async findOneTemplate(tenantId: number, id: number) {
    const template = await this.prisma.taskTemplate.findFirst({
      where: {
        id: id,
        tenantId: tenantId,
      },
      include: {
        course: {
          select: {
            id: true,
            name: true,
            pictureBookName: true,
          },
        },
      },
    });

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

    return template;
  }

  async createTemplate(tenantId: number, userId: number, dto: CreateTaskTemplateDto) {
    // 如果设置为默认，先取消其他同类型的默认模板
    if (dto.isDefault) {
      await this.prisma.taskTemplate.updateMany({
        where: {
          tenantId,
          taskType: dto.taskType,
          isDefault: true,
        },
        data: { isDefault: false },
      });
    }

    const template = await this.prisma.taskTemplate.create({
      data: {
        tenantId: tenantId,
        name: dto.name,
        description: dto.description,
        taskType: dto.taskType,
        relatedCourseId: dto.relatedCourseId,
        defaultDuration: dto.defaultDuration || 7,
        isDefault: dto.isDefault || false,
        createdBy: userId,
      },
      include: {
        course: {
          select: {
            id: true,
            name: true,
            pictureBookName: true,
          },
        },
      },
    });

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

    return template;
  }

  async updateTemplate(tenantId: number, id: number, dto: UpdateTaskTemplateDto) {
    const existing = await this.prisma.taskTemplate.findFirst({
      where: { id, tenantId },
    });

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

    // 如果设置为默认，先取消其他同类型的默认模板
    if (dto.isDefault) {
      await this.prisma.taskTemplate.updateMany({
        where: {
          tenantId,
          taskType: existing.taskType,
          isDefault: true,
          id: { not: id },
        },
        data: { isDefault: false },
      });
    }

    const template = await this.prisma.taskTemplate.update({
      where: { id },
      data: {
        name: dto.name,
        description: dto.description,
        relatedCourseId: dto.relatedCourseId,
        defaultDuration: dto.defaultDuration,
        isDefault: dto.isDefault,
        status: dto.status,
      },
      include: {
        course: {
          select: {
            id: true,
            name: true,
            pictureBookName: true,
          },
        },
      },
    });

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

    return template;
  }

  async deleteTemplate(tenantId: number, id: number) {
    const existing = await this.prisma.taskTemplate.findFirst({
      where: { id, tenantId },
    });

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

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

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

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

  async getDefaultTemplate(tenantId: number, taskType: string) {
    const template = await this.prisma.taskTemplate.findFirst({
      where: {
        tenantId,
        taskType,
        isDefault: true,
        status: 'ACTIVE',
      },
      include: {
        course: {
          select: {
            id: true,
            name: true,
            pictureBookName: true,
          },
        },
      },
    });

    return template;
  }

  // 从模板创建任务
  async createFromTemplate(
    tenantId: number,
    userId: number,
    templateId: number,
    dto: { targetIds: number[]; targetType: string; startDate?: string },
  ) {
    const template = await this.findOneTemplate(tenantId, templateId);

    const start = dto.startDate ? new Date(dto.startDate) : new Date();
    const end = new Date(start);
    end.setDate(end.getDate() + template.defaultDuration);

    const task = await this.create(tenantId, userId, {
      title: template.name,
      description: template.description,
      taskType: template.taskType as any,
      targetType: dto.targetType as any,
      targetIds: dto.targetIds,
      relatedCourseId: template.relatedCourseId,
      startDate: start.toISOString().split('T')[0],
      endDate: end.toISOString().split('T')[0],
    });

    this.logger.log(`Task created from template: template=${templateId}, task=${task.id}`);

    return task;
  }
}
