package com.lesingle.edu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.lesingle.edu.common.enums.CourseStatus;
import com.lesingle.edu.dto.request.CourseUsageQuery;
import com.lesingle.edu.dto.response.*;
import com.lesingle.edu.entity.Clazz;
import com.lesingle.edu.entity.CoursePackage;
import com.lesingle.edu.entity.Lesson;
import com.lesingle.edu.entity.Student;
import com.lesingle.edu.mapper.ClazzMapper;
import com.lesingle.edu.mapper.CoursePackageMapper;
import com.lesingle.edu.mapper.LessonMapper;
import com.lesingle.edu.mapper.StudentMapper;
import com.lesingle.edu.mapper.struct.TeacherStatsMapperStruct;
import com.lesingle.edu.service.TeacherStatsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 教师统计服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TeacherStatsServiceImpl implements TeacherStatsService {

    private final ClazzMapper clazzMapper;
    private final StudentMapper studentMapper;
    private final CoursePackageMapper courseMapper;
    private final LessonMapper lessonMapper;

    @Override
    public TeacherDashboardResponse getDashboard(Long teacherId, Long tenantId) {
        // 基础统计
        TeacherDashboardResponse.TeacherStats stats = TeacherDashboardResponse.TeacherStats.builder()
                .classCount(clazzMapper.selectCount(
                        new LambdaQueryWrapper<Clazz>().eq(Clazz::getTenantId, tenantId)
                ))
                .studentCount(studentMapper.selectCount(
                        new LambdaQueryWrapper<Student>().eq(Student::getTenantId, tenantId)
                ))
                .courseCount(courseMapper.selectCount(
                        new LambdaQueryWrapper<CoursePackage>().eq(CoursePackage::getTenantId, tenantId)
                ))
                .build();

        // Lesson count (handle missing table gracefully)
        long lessonCount = 0;
        try {
            lessonCount = lessonMapper.selectCount(
                    new LambdaQueryWrapper<Lesson>().eq(Lesson::getTeacherId, teacherId)
            );
        } catch (Exception e) {
            log.warn("Failed to query lessons table: {}", e.getMessage());
        }
        stats.setLessonCount(lessonCount);

        // 今日课程
        List<TeacherLessonVO> todayLessons = getTodayLessons(teacherId);

        // 推荐课程（热门课程）
        List<CoursePackageVO> recommendedCourses = getRecommendedCourses(tenantId);

        // 本周统计
        TeacherWeeklyStatsResponse weeklyStats = getWeeklyStats(teacherId);

        // 近期活动（暂空）
        List<Object> recentActivities = new ArrayList<>();

        return TeacherDashboardResponse.builder()
                .stats(stats)
                .todayLessons(todayLessons)
                .recommendedCourses(recommendedCourses)
                .weeklyStats(weeklyStats)
                .recentActivities(recentActivities)
                .build();
    }

    @Override
    public List<TeacherLessonVO> getTodayLessons(Long teacherId) {
        LocalDate today = LocalDate.now();
        try {
            // 使用自定义查询，关联获取课程名称和班级名称
            List<Map<String, Object>> resultList = lessonMapper.selectTodayLessonsWithDetails(teacherId, today);

            List<TeacherLessonVO> voList = new ArrayList<>();
            for (Map<String, Object> row : resultList) {
                TeacherLessonVO vo = TeacherLessonVO.builder()
                        .id(getLong(row.get("id")))
                        .tenantId(getLong(row.get("tenant_id")))
                        .courseId(getLong(row.get("course_id")))
                        .classId(getLong(row.get("class_id")))
                        .teacherId(getLong(row.get("teacher_id")))
                        .courseName(getString(row.get("courseName")))
                        .className(getString(row.get("className")))
                        .title(getString(row.get("title")))
                        .lessonDate(getLocalDate(row.get("lesson_date")))
                        .startTime(getLocalTime(row.get("start_time")))
                        .endTime(getLocalTime(row.get("end_time")))
                        .location(getString(row.get("location")))
                        .status(getString(row.get("status")))
                        .notes(getString(row.get("notes")))
                        .createdAt(getLocalDateTime(row.get("created_at")))
                        .updatedAt(getLocalDateTime(row.get("updated_at")))
                        .build();
                voList.add(vo);
            }
            return voList;
        } catch (Exception e) {
            log.warn("Failed to query today lessons: {}", e.getMessage());
            return new ArrayList<>();
        }
    }

    /**
     * 辅助方法：安全获取 Long 类型值
     */
    private Long getLong(Object value) {
        if (value == null) return null;
        if (value instanceof Long) return (Long) value;
        if (value instanceof Number) return ((Number) value).longValue();
        try {
            return Long.parseLong(value.toString());
        } catch (NumberFormatException e) {
            return null;
        }
    }

    /**
     * 辅助方法：安全获取 String 类型值
     */
    private String getString(Object value) {
        if (value == null) return null;
        return value.toString();
    }

    /**
     * 辅助方法：安全获取 LocalDate 类型值
     */
    private LocalDate getLocalDate(Object value) {
        if (value == null) return null;
        if (value instanceof LocalDate) return (LocalDate) value;
        try {
            if (value instanceof java.sql.Date) {
                return ((java.sql.Date) value).toLocalDate();
            }
            return LocalDate.parse(value.toString());
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 辅助方法：安全获取 LocalTime 类型值
     */
    private LocalTime getLocalTime(Object value) {
        if (value == null) return null;
        if (value instanceof LocalTime) return (LocalTime) value;
        try {
            if (value instanceof java.sql.Time) {
                return ((java.sql.Time) value).toLocalTime();
            }
            return LocalTime.parse(value.toString());
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 辅助方法：安全获取 LocalDateTime 类型值
     */
    private LocalDateTime getLocalDateTime(Object value) {
        if (value == null) return null;
        if (value instanceof LocalDateTime) return (LocalDateTime) value;
        try {
            if (value instanceof java.sql.Timestamp) {
                return ((java.sql.Timestamp) value).toLocalDateTime();
            }
            return LocalDateTime.parse(value.toString());
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public List<CoursePackageVO> getRecommendedCourses(Long tenantId) {
        List<CoursePackage> coursePackages = courseMapper.selectList(
                new LambdaQueryWrapper<CoursePackage>()
                        .eq(CoursePackage::getTenantId, tenantId)
                        .eq(CoursePackage::getStatus, CourseStatus.PUBLISHED.getCode())
                        .orderByDesc(CoursePackage::getUsageCount)
                        .last("LIMIT 10")
        );
        return TeacherStatsMapperStruct.INSTANCE.toCoursePackageVOList(coursePackages);
    }

    @Override
    public TeacherWeeklyStatsResponse getWeeklyStats(Long teacherId) {
        LocalDate weekAgo = LocalDate.now().minusDays(7);
        long lessonCount = 0;
        try {
            lessonCount = lessonMapper.selectCount(
                    new LambdaQueryWrapper<Lesson>()
                            .eq(Lesson::getTeacherId, teacherId)
                            .ge(Lesson::getLessonDate, weekAgo)
            );
        } catch (Exception e) {
            log.warn("Failed to query weekly lesson count: {}", e.getMessage());
        }

        return TeacherWeeklyStatsResponse.builder()
                .lessonCount(lessonCount)
                .studentParticipation(85) // TODO: calculate actual participation
                .avgRating(4.5) // TODO: calculate actual rating
                .totalDuration(300) // TODO: calculate actual duration
                .build();
    }

    @Override
    public List<TeacherLessonTrendVO> getLessonTrend(Long teacherId, int months) {
        List<TeacherLessonTrendVO> trend = new ArrayList<>();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM");

        for (int i = months - 1; i >= 0; i--) {
            LocalDate date = LocalDate.now().minusMonths(i);
            String month = date.format(formatter);
            LocalDate monthStart = date.withDayOfMonth(1);
            LocalDate monthEnd = date.plusMonths(1).withDayOfMonth(1);

            long lessonCount = 0;
            try {
                lessonCount = lessonMapper.selectCount(
                        new LambdaQueryWrapper<Lesson>()
                                .eq(Lesson::getTeacherId, teacherId)
                                .ge(Lesson::getLessonDate, monthStart)
                                .lt(Lesson::getLessonDate, monthEnd)
                );
            } catch (Exception e) {
                log.warn("Failed to query lesson trend for {}: {}", month, e.getMessage());
            }

            trend.add(TeacherLessonTrendVO.builder()
                    .month(month)
                    .lessonCount(lessonCount)
                    .avgRating(4.5) // TODO: calculate actual rating
                    .build());
        }

        return trend;
    }

    @Override
    public List<CourseUsageVO> getCourseUsage(Long tenantId) {
        List<CourseUsageVO> usage = new ArrayList<>();

        List<CoursePackage> courses = courseMapper.selectList(
                new LambdaQueryWrapper<CoursePackage>()
                        .eq(CoursePackage::getTenantId, tenantId)
                        .orderByDesc(CoursePackage::getUsageCount)
                        .last("LIMIT 10")
        );

        for (CoursePackage course : courses) {
            usage.add(CourseUsageVO.builder()
                    .name(course.getName())
                    .value(course.getUsageCount() != null ? course.getUsageCount() : 0)
                    .build());
        }

        return usage;
    }

    @Override
    public List<CourseUsageStatsVO> getCourseUsageStats(Long tenantId, Long teacherId, CourseUsageQuery query) {
        // 计算时间范围
        LocalDateTime[] timeRange = calculateTimeRange(query);

        // 调用 Mapper 查询
        return lessonMapper.getCourseUsageStats(tenantId, teacherId, timeRange[0], timeRange[1]);
    }

    /**
     * 根据周期类型计算时间范围
     */
    private LocalDateTime[] calculateTimeRange(CourseUsageQuery query) {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime startTime;
        LocalDateTime endTime = now;

        String periodType = query != null ? query.getPeriodType() : "MONTH";

        switch (periodType) {
            case "TODAY":
                startTime = now.toLocalDate().atStartOfDay();
                break;
            case "WEEK":
                // 本周一
                startTime = now.toLocalDate()
                        .with(DayOfWeek.MONDAY)
                        .atStartOfDay();
                break;
            case "MONTH":
                // 本月 1 号
                startTime = now.toLocalDate()
                        .withDayOfMonth(1)
                        .atStartOfDay();
                break;
            case "CUSTOM":
                if (query.getStartDate() != null) {
                    startTime = query.getStartDate().atStartOfDay();
                } else {
                    startTime = now.minusMonths(1);
                }
                if (query.getEndDate() != null) {
                    endTime = query.getEndDate().atTime(23, 59, 59);
                }
                break;
            default:
                startTime = now.toLocalDate().withDayOfMonth(1).atStartOfDay();
        }

        return new LocalDateTime[]{startTime, endTime};
    }
}
