package com.reading.platform.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.reading.platform.dto.response.*;
import com.reading.platform.entity.*;
import com.reading.platform.mapper.*;
import com.reading.platform.service.SchoolReportService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 学校报告服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SchoolReportServiceImpl implements SchoolReportService {

    private final TeacherMapper teacherMapper;
    private final StudentMapper studentMapper;
    private final ClazzMapper clazzMapper;
    private final CourseMapper courseMapper;
    private final LessonMapper lessonMapper;
    private final TaskMapper taskMapper;
    private final GrowthRecordMapper growthRecordMapper;
    private final ClassTeacherMapper classTeacherMapper;
    private final LessonFeedbackMapper lessonFeedbackMapper;
    private final StudentRecordMapper studentRecordMapper;
    private final TaskCompletionMapper taskCompletionMapper;

    @Override
    public SchoolOverviewStatsResponse getOverviewStats(String tenantId) {
        SchoolOverviewStatsResponse response = new SchoolOverviewStatsResponse();

        // 教师统计
        response.setTeacherCount(Math.toIntExact(teacherMapper.selectCount(
                new LambdaQueryWrapper<Teacher>().eq(Teacher::getTenantId, tenantId))));

        // 学生统计
        response.setStudentCount(Math.toIntExact(studentMapper.selectCount(
                new LambdaQueryWrapper<Student>().eq(Student::getTenantId, tenantId))));

        // 班级统计
        response.setClassCount(Math.toIntExact(clazzMapper.selectCount(
                new LambdaQueryWrapper<Clazz>().eq(Clazz::getTenantId, tenantId))));

        // 课程统计（校本课程）
        response.setCourseCount(Math.toIntExact(courseMapper.selectCount(
                new LambdaQueryWrapper<Course>().eq(Course::getTenantId, tenantId))));

        // 课时统计
        LocalDate monthStart = LocalDate.now().withDayOfMonth(1);
        response.setMonthlyLessons(Math.toIntExact(lessonMapper.selectCount(
                new LambdaQueryWrapper<Lesson>()
                        .eq(Lesson::getTenantId, tenantId)
                        .ge(Lesson::getLessonDate, monthStart))));
        response.setTotalLessons(Math.toIntExact(lessonMapper.selectCount(
                new LambdaQueryWrapper<Lesson>().eq(Lesson::getTenantId, tenantId))));

        // 任务统计
        response.setMonthlyTasks(Math.toIntExact(taskMapper.selectCount(
                new LambdaQueryWrapper<Task>()
                        .eq(Task::getTenantId, tenantId)
                        .ge(Task::getCreatedAt, monthStart))));
        response.setTotalTasks(Math.toIntExact(taskMapper.selectCount(
                new LambdaQueryWrapper<Task>().eq(Task::getTenantId, tenantId))));

        // 成长记录统计
        response.setMonthlyGrowthRecords(Math.toIntExact(growthRecordMapper.selectCount(
                new LambdaQueryWrapper<GrowthRecord>()
                        .eq(GrowthRecord::getTenantId, tenantId)
                        .ge(GrowthRecord::getCreatedAt, monthStart))));
        response.setTotalGrowthRecords(Math.toIntExact(growthRecordMapper.selectCount(
                new LambdaQueryWrapper<GrowthRecord>().eq(GrowthRecord::getTenantId, tenantId))));

        return response;
    }

    @Override
    public List<TeacherStatsReportResponse> getTeacherStats(String tenantId) {
        List<Teacher> teachers = teacherMapper.selectList(
                new LambdaQueryWrapper<Teacher>().eq(Teacher::getTenantId, tenantId));

        return teachers.stream().map(teacher -> {
            TeacherStatsReportResponse response = new TeacherStatsReportResponse();
            response.setTeacherId(teacher.getId().toString());
            response.setTeacherName(teacher.getName());

            // 授课班级数
            Long classCount = classTeacherMapper.selectCount(
                    new LambdaQueryWrapper<ClassTeacher>().eq(ClassTeacher::getTeacherId, teacher.getId()));
            response.setClassCount(Math.toIntExact(classCount));

            // 学生数（所教班级的学生）
            List<String> classIds = classTeacherMapper.selectList(
                    new LambdaQueryWrapper<ClassTeacher>()
                            .eq(ClassTeacher::getTeacherId, teacher.getId()))
                    .stream().map(ClassTeacher::getClassId).collect(Collectors.toList());

            if (!classIds.isEmpty()) {
                Long studentCount = studentMapper.selectCount(
                        new LambdaQueryWrapper<Student>()
                                .eq(Student::getTenantId, tenantId)
                                .in(Student::getClassId, classIds));
                response.setStudentCount(Math.toIntExact(studentCount));
            } else {
                response.setStudentCount(0);
            }

            // 课时统计
            LocalDate monthStart = LocalDate.now().withDayOfMonth(1);
            response.setMonthlyLessons(Math.toIntExact(lessonMapper.selectCount(
                    new LambdaQueryWrapper<Lesson>()
                            .eq(Lesson::getTeacherId, teacher.getId().toString())
                            .ge(Lesson::getLessonDate, monthStart))));
            response.setTotalLessons(Math.toIntExact(lessonMapper.selectCount(
                    new LambdaQueryWrapper<Lesson>().eq(Lesson::getTeacherId, teacher.getId().toString()))));

            // 反馈统计
            List<LessonFeedback> feedbacks = lessonFeedbackMapper.selectList(
                    new LambdaQueryWrapper<LessonFeedback>()
                            .eq(LessonFeedback::getTeacherId, teacher.getId().toString()));
            response.setFeedbackCount(feedbacks.size());

            if (!feedbacks.isEmpty()) {
                double avgRating = feedbacks.stream()
                        .filter(f -> f.getOverallRating() != null)
                        .mapToInt(LessonFeedback::getOverallRating)
                        .average()
                        .orElse(0.0);
                response.setAvgRating(Math.round(avgRating * 10) / 10.0);
            } else {
                response.setAvgRating(0.0);
            }

            return response;
        }).collect(Collectors.toList());
    }

    @Override
    public List<CourseStatsReportResponse> getCourseStats(String tenantId) {
        List<Course> courses = courseMapper.selectList(
                new LambdaQueryWrapper<Course>().eq(Course::getTenantId, tenantId));

        return courses.stream().map(course -> {
            CourseStatsReportResponse response = new CourseStatsReportResponse();
            response.setCourseId(course.getId().toString());
            response.setCourseName(course.getName());
            response.setCategory(course.getCategory());

            // 使用教师数
            Long teacherCount = lessonMapper.selectCount(
                    new LambdaQueryWrapper<Lesson>()
                            .eq(Lesson::getCourseId, course.getId())
                            .eq(Lesson::getTenantId, tenantId)
                            .groupBy(Lesson::getTeacherId));
            response.setTeacherCount(Math.toIntExact(teacherCount));

            // 使用班级数
            Long classCount = lessonMapper.selectCount(
                    new LambdaQueryWrapper<Lesson>()
                            .eq(Lesson::getCourseId, course.getId())
                            .eq(Lesson::getTenantId, tenantId)
                            .groupBy(Lesson::getClassId));
            response.setClassCount(Math.toIntExact(classCount));

            // 课时统计
            LocalDate monthStart = LocalDate.now().withDayOfMonth(1);
            response.setMonthlyLessons(Math.toIntExact(lessonMapper.selectCount(
                    new LambdaQueryWrapper<Lesson>()
                            .eq(Lesson::getCourseId, course.getId())
                            .ge(Lesson::getLessonDate, monthStart))));
            response.setTotalLessons(Math.toIntExact(lessonMapper.selectCount(
                    new LambdaQueryWrapper<Lesson>().eq(Lesson::getCourseId, course.getId()))));

            // 平均评分
            List<LessonFeedback> feedbacks = lessonFeedbackMapper.selectList(
                    new LambdaQueryWrapper<LessonFeedback>()
                            .eq(LessonFeedback::getCourseId, course.getId()));
            if (!feedbacks.isEmpty()) {
                double avgRating = feedbacks.stream()
                        .filter(f -> f.getOverallRating() != null)
                        .mapToInt(LessonFeedback::getOverallRating)
                        .average()
                        .orElse(0.0);
                response.setAvgRating(Math.round(avgRating * 10) / 10.0);
            } else {
                response.setAvgRating(0.0);
            }

            return response;
        }).collect(Collectors.toList());
    }

    @Override
    public List<StudentStatsReportResponse> getStudentStats(String tenantId, String classId) {
        LambdaQueryWrapper<Student> wrapper = new LambdaQueryWrapper<Student>()
                .eq(Student::getTenantId, tenantId);
        if (classId != null && !classId.isEmpty()) {
            wrapper.eq(Student::getClassId, classId);
        }

        List<Student> students = studentMapper.selectList(wrapper);

        return students.stream().map(student -> {
            StudentStatsReportResponse response = new StudentStatsReportResponse();
            response.setStudentId(student.getId().toString());
            response.setStudentName(student.getName());
            response.setClassId(student.getClassId() != null ? student.getClassId().toString() : null);

            // 班级名称
            if (student.getClassId() != null) {
                Clazz clazz = clazzMapper.selectById(student.getClassId());
                if (clazz != null) {
                    response.setClassName(clazz.getName());
                }
            }

            // 课时统计
            LocalDate monthStart = LocalDate.now().withDayOfMonth(1);
            response.setMonthlyLessons(Math.toIntExact(studentRecordMapper.selectCount(
                    new LambdaQueryWrapper<StudentRecord>()
                            .eq(StudentRecord::getStudentId, student.getId())
                            .ge(StudentRecord::getCreatedAt, monthStart))));
            response.setTotalLessons(Math.toIntExact(studentRecordMapper.selectCount(
                    new LambdaQueryWrapper<StudentRecord>().eq(StudentRecord::getStudentId, student.getId()))));

            // 任务完成数
            response.setCompletedTasks(Math.toIntExact(taskCompletionMapper.selectCount(
                    new LambdaQueryWrapper<TaskCompletion>()
                            .eq(TaskCompletion::getStudentId, student.getId())
                            .eq(TaskCompletion::getStatus, "completed"))));

            // 成长记录数
            response.setGrowthRecordCount(Math.toIntExact(growthRecordMapper.selectCount(
                    new LambdaQueryWrapper<GrowthRecord>()
                            .eq(GrowthRecord::getStudentId, student.getId()))));

            // 平均专注力和参与度
            List<StudentRecord> records = studentRecordMapper.selectList(
                    new LambdaQueryWrapper<StudentRecord>()
                            .eq(StudentRecord::getStudentId, student.getId()));
            if (!records.isEmpty()) {
                double avgFocus = records.stream()
                        .filter(r -> r.getFocus() != null)
                        .mapToInt(StudentRecord::getFocus)
                        .average()
                        .orElse(0.0);
                double avgParticipation = records.stream()
                        .filter(r -> r.getParticipation() != null)
                        .mapToInt(StudentRecord::getParticipation)
                        .average()
                        .orElse(0.0);
                response.setAvgFocus(Math.round(avgFocus * 10) / 10.0);
                response.setAvgParticipation(Math.round(avgParticipation * 10) / 10.0);
            } else {
                response.setAvgFocus(0.0);
                response.setAvgParticipation(0.0);
            }

            return response;
        }).collect(Collectors.toList());
    }

    @Override
    public List<LessonTrendDataPoint> getLessonTrend(String tenantId, Integer months) {
        int monthLimit = months != null ? months : 6;
        List<LessonTrendDataPoint> trend = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");
        LocalDate now = LocalDate.now();

        for (int i = monthLimit - 1; i >= 0; i--) {
            LocalDate monthStart = now.minusMonths(i).withDayOfMonth(1);
            LocalDate monthEnd = monthStart.plusMonths(1).minusDays(1);

            long lessonCount = lessonMapper.selectCount(
                    new LambdaQueryWrapper<Lesson>()
                            .eq(Lesson::getTenantId, tenantId)
                            .between(Lesson::getLessonDate, monthStart, monthEnd));

            trend.add(createTrendDataPoint(monthStart, monthEnd, tenantId, lessonCount, formatter));
        }

        log.info("获取课时趋势：tenantId={}, 月份数={}, 数据点数={}", tenantId, monthLimit, trend.size());
        return trend;
    }

    private LessonTrendDataPoint createTrendDataPoint(LocalDate monthStart, LocalDate monthEnd,
                                                       String tenantId, long lessonCount, DateTimeFormatter formatter) {
        LessonTrendDataPoint point = new LessonTrendDataPoint();
        point.setMonth(monthStart.format(formatter));
        point.setLessonCount(Math.toIntExact(lessonCount));

        // 统计该月的教师数（有课时的教师）
        Set<String> teacherIds = lessonMapper.selectList(
                new LambdaQueryWrapper<Lesson>()
                        .eq(Lesson::getTenantId, tenantId)
                        .between(Lesson::getLessonDate, monthStart, monthEnd)
                        .isNotNull(Lesson::getTeacherId))
                .stream()
                .map(Lesson::getTeacherId)
                .collect(Collectors.toSet());
        point.setTeacherCount(teacherIds.size());

        // 统计该月有课时记录的学生数
        List<StudentRecord> records = studentRecordMapper.selectList(
                new LambdaQueryWrapper<StudentRecord>()
                        .ge(StudentRecord::getCreatedAt, monthStart.atStartOfDay())
                        .lt(StudentRecord::getCreatedAt, monthEnd.atTime(23, 59, 59)));

        Set<String> studentIds = records.stream()
                .map(StudentRecord::getStudentId)
                .collect(Collectors.toSet());
        point.setStudentCount(studentIds.size());

        return point;
    }
}
