package com.example.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.common.enums.ResultCodeEnum;
import com.example.common.config.TokenUtils;
import com.example.entity.Account;
import com.example.entity.AssessmentReport;
import com.example.entity.Patient;
import com.example.entity.SymptomRecord;
import com.example.exception.CustomException;
import com.example.mapper.AssessmentReportMapper;
import com.example.mapper.SymptomRecordMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.scheduling.annotation.Scheduled;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Date;
import java.util.DoubleSummaryStatistics;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.HashMap;

@Service
public class AssessmentReportService {

    @Resource
    private AssessmentReportMapper assessmentReportMapper;
    
    @Resource
    private SymptomRecordMapper symptomRecordMapper;
    
    @Resource
    private PatientService patientService;
    
    /**
     * 生成评估报告
     * @param patientId 患者ID
     * @param reportPeriod 报告周期类型（"week"/"month"）
     * @return 生成的评估报告
     */
    public AssessmentReport generateReport(Integer patientId, String reportPeriod) {
        // 获取当前用户
        Account currentUser = TokenUtils.getCurrentUser();
        if (currentUser == null) {
            throw new CustomException(ResultCodeEnum.TOKEN_CHECK_ERROR);
        }
        
        // 验证权限
        String role = currentUser.getRole();
        if (!"admin".equals(role) && !"doctor".equals(role) && 
            (!"patient".equals(role) || !currentUser.getId().equals(patientId))) {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR.code, "无权生成该患者的评估报告");
        }
        
        // 设置报告时间范围
        LocalDate endDate = LocalDate.now();
        LocalDate startDate;
        
        if ("week".equals(reportPeriod)) {
            startDate = endDate.minusWeeks(1);
        } else if ("month".equals(reportPeriod)) {
            startDate = endDate.minusMonths(1);
        } else {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR.code, "无效的报告周期类型");
        }
        
        // 获取时间范围内的症状记录
        List<SymptomRecord> records = symptomRecordMapper.selectByPatientIdAndDateRange(
                patientId, startDate, endDate);
        
        if (records.isEmpty()) {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR.code, "所选时间范围内没有症状记录");
        }
        
        // 创建评估报告
        AssessmentReport report = new AssessmentReport();
        report.setPatientId(patientId);
        report.setReportPeriod("week".equals(reportPeriod) ? "周报" : "月报");
        report.setStartDate(startDate);
        report.setEndDate(endDate);
        report.setStatus("未读");
        report.setCreateTime(LocalDateTime.now());
        
        // 生成报告内容
        generateReportContent(report, records);
        
        // 保存报告
        assessmentReportMapper.insert(report);
        
        return report;
    }
    
    /**
     * 生成报告内容
     */
    private void generateReportContent(AssessmentReport report, List<SymptomRecord> records) {
        // 计算统计数据
        DoubleSummaryStatistics severityStats = records.stream()
                .map(SymptomRecord::getSeverityLevel)
                .filter(val -> val != null)
                .mapToDouble(Integer::doubleValue)
                .summaryStatistics();
                
        DoubleSummaryStatistics emotionStats = records.stream()
                .map(SymptomRecord::getEmotionScore)
                .filter(val -> val != null)
                .mapToDouble(Integer::doubleValue)
                .summaryStatistics();
                
        DoubleSummaryStatistics sleepStats = records.stream()
                .map(SymptomRecord::getSleepTime)
                .filter(val -> val != null)
                .mapToDouble(Integer::doubleValue)
                .summaryStatistics();
                
        // 生成总体评估
        StringBuilder summary = new StringBuilder();
        summary.append("本")
               .append(report.getReportPeriod())
               .append("期间（")
               .append(report.getStartDate().format(DateTimeFormatter.ISO_LOCAL_DATE))
               .append(" 至 ")
               .append(report.getEndDate().format(DateTimeFormatter.ISO_LOCAL_DATE))
               .append("），共记录了 ")
               .append(records.size())
               .append(" 条症状数据。\n\n");
               
        summary.append("严重程度评分：平均 ")
               .append(String.format("%.1f", severityStats.getAverage()))
               .append("，最高 ")
               .append((int)severityStats.getMax())
               .append("，最低 ")
               .append((int)severityStats.getMin())
               .append("。\n");
               
        summary.append("情绪基线评分：平均 ")
               .append(String.format("%.1f", emotionStats.getAverage()))
               .append("，最高 ")
               .append((int)emotionStats.getMax())
               .append("，最低 ")
               .append((int)emotionStats.getMin())
               .append("。\n");
               
        summary.append("入睡时间：平均 ")
               .append(String.format("%.1f", sleepStats.getAverage()))
               .append(" 分钟，最长 ")
               .append((int)sleepStats.getMax())
               .append(" 分钟，最短 ")
               .append((int)sleepStats.getMin())
               .append(" 分钟。\n");
        
        // 设置总体评估
        report.setSummary(summary.toString());
        
        // 生成趋势分析
        StringBuilder trend = new StringBuilder();
        
        // 按记录时间转换为LocalDate进行分组
        Map<LocalDate, List<SymptomRecord>> recordsByDate = new HashMap<>();
        for (SymptomRecord record : records) {
            Date recordTime = record.getRecordTime();
            if (recordTime != null) {
                LocalDate recordDate = new java.sql.Date(recordTime.getTime()).toLocalDate();
                if (!recordsByDate.containsKey(recordDate)) {
                    recordsByDate.put(recordDate, new ArrayList<>());
                }
                recordsByDate.get(recordDate).add(record);
            }
        }
        
        // 获取排序后的日期列表
        List<LocalDate> dates = new ArrayList<>(recordsByDate.keySet());
        dates.sort(LocalDate::compareTo);
        
        if (dates.size() > 1) {
            // 计算首尾日期的平均严重程度
            double firstDaySeverity = recordsByDate.get(dates.get(0)).stream()
                    .map(SymptomRecord::getSeverityLevel)
                    .filter(val -> val != null)
                    .mapToDouble(Integer::doubleValue)
                    .average()
                    .orElse(0);
                    
            double lastDaySeverity = recordsByDate.get(dates.get(dates.size() - 1)).stream()
                    .map(SymptomRecord::getSeverityLevel)
                    .filter(val -> val != null)
                    .mapToDouble(Integer::doubleValue)
                    .average()
                    .orElse(0);
            
            // 趋势分析
            trend.append("症状严重程度：");
            if (lastDaySeverity < firstDaySeverity) {
                trend.append("整体呈下降趋势，相比初始记录降低了 ")
                     .append(String.format("%.1f", firstDaySeverity - lastDaySeverity))
                     .append(" 点，病情有所好转。");
            } else if (lastDaySeverity > firstDaySeverity) {
                trend.append("整体呈上升趋势，相比初始记录增加了 ")
                     .append(String.format("%.1f", lastDaySeverity - firstDaySeverity))
                     .append(" 点，病情有所加重。");
            } else {
                trend.append("整体保持稳定，症状严重程度变化不明显。");
            }
            trend.append("\n\n");
            
            // 情绪基线趋势分析
            double firstDayEmotion = recordsByDate.get(dates.get(0)).stream()
                    .map(SymptomRecord::getEmotionScore)
                    .filter(val -> val != null)
                    .mapToDouble(Integer::doubleValue)
                    .average()
                    .orElse(0);
                    
            double lastDayEmotion = recordsByDate.get(dates.get(dates.size() - 1)).stream()
                    .map(SymptomRecord::getEmotionScore)
                    .filter(val -> val != null)
                    .mapToDouble(Integer::doubleValue)
                    .average()
                    .orElse(0);
                    
            trend.append("情绪状态：");
            if (lastDayEmotion > firstDayEmotion) {
                trend.append("呈积极改善趋势，情绪基线提高了 ")
                     .append(String.format("%.1f", lastDayEmotion - firstDayEmotion))
                     .append(" 点。");
            } else if (lastDayEmotion < firstDayEmotion) {
                trend.append("呈下降趋势，情绪基线降低了 ")
                     .append(String.format("%.1f", firstDayEmotion - lastDayEmotion))
                     .append(" 点，需要关注情绪变化。");
            } else {
                trend.append("情绪基线保持稳定。");
            }
        } else {
            trend.append("记录天数不足，无法进行趋势分析。建议持续记录症状，以便更准确地评估病情变化。");
        }
        
        // 设置趋势分析
        report.setTrendAnalysis(trend.toString());
        
        // 生成建议
        StringBuilder recommendation = new StringBuilder();
        
        // 基于严重程度的建议
        double avgSeverity = severityStats.getAverage();
        if (avgSeverity >= 7) {
            recommendation.append("● 症状严重程度较高，建议及时就医或保持与医生的密切沟通。\n");
            recommendation.append("● 注意休息，避免过度劳累和压力。\n");
        } else if (avgSeverity >= 4) {
            recommendation.append("● 症状处于中等程度，建议遵循医嘱进行调整。\n");
            recommendation.append("● 可以尝试适当的放松训练和心理调适方法。\n");
        } else {
            recommendation.append("● 症状程度较轻，建议继续保持良好的生活习惯。\n");
        }
        
        // 基于情绪状态的建议
        double avgEmotion = emotionStats.getAverage();
        if (avgEmotion <= 4) {
            recommendation.append("● 情绪基线较低，建议尝试以下方法改善情绪：\n");
            recommendation.append("  - 每天进行至少30分钟的适当运动\n");
            recommendation.append("  - 学习简单的冥想或深呼吸放松技巧\n");
            recommendation.append("  - 与亲友多交流，分享感受\n");
        }
        
        // 基于睡眠情况的建议
        double avgSleep = sleepStats.getAverage();
        if (avgSleep > 30) {
            recommendation.append("● 入睡时间较长，建议改善睡眠习惯：\n");
            recommendation.append("  - 保持规律的睡眠时间表\n");
            recommendation.append("  - 睡前一小时避免使用电子设备\n");
            recommendation.append("  - 睡前可以喝杯温热的牛奶或进行轻度放松活动\n");
        }
        
        // 一般性建议
        recommendation.append("\n持续记录症状变化，这将帮助您和医生更好地了解病情发展，制定更适合的治疗方案。");
        
        // 设置建议
        report.setRecommendation(recommendation.toString());
    }
    
    /**
     * 每周一凌晨2点自动生成周报
     */
    @Scheduled(cron = "0 0 2 ? * MON")
    public void generateWeeklyReports() {
        List<Account> patients = getPatients();
        for (Account patient : patients) {
            try {
                generateReportForPatient(patient.getId(), "week");
            } catch (Exception e) {
                // 记录错误但不中断流程
                System.err.println("为患者 " + patient.getId() + " 生成周报失败: " + e.getMessage());
            }
        }
    }
    
    /**
     * 每月1日凌晨3点自动生成月报
     */
    @Scheduled(cron = "0 0 3 1 * ?")
    public void generateMonthlyReports() {
        List<Account> patients = getPatients();
        for (Account patient : patients) {
            try {
                generateReportForPatient(patient.getId(), "month");
            } catch (Exception e) {
                // 记录错误但不中断流程
                System.err.println("为患者 " + patient.getId() + " 生成月报失败: " + e.getMessage());
            }
        }
    }
    
    /**
     * 为患者生成报告（内部方法，用于定时任务）
     */
    private AssessmentReport generateReportForPatient(Integer patientId, String reportPeriod) {
        LocalDate endDate = LocalDate.now();
        LocalDate startDate;
        
        if ("week".equals(reportPeriod)) {
            startDate = endDate.minusWeeks(1);
        } else {
            startDate = endDate.minusMonths(1);
        }
        
        // 获取时间范围内的症状记录
        List<SymptomRecord> records = symptomRecordMapper.selectByPatientIdAndDateRange(
                patientId, startDate, endDate);
        
        // 如果没有记录，则不生成报告
        if (records.isEmpty()) {
            return null;
        }
        
        // 创建评估报告
        AssessmentReport report = new AssessmentReport();
        report.setPatientId(patientId);
        report.setReportPeriod("week".equals(reportPeriod) ? "周报" : "月报");
        report.setStartDate(startDate);
        report.setEndDate(endDate);
        report.setStatus("未读");
        report.setCreateTime(LocalDateTime.now());
        
        // 生成报告内容
        generateReportContent(report, records);
        
        // 保存报告
        assessmentReportMapper.insert(report);
        
        return report;
    }
    
    /**
     * 获取所有患者列表
     */
    private List<Account> getPatients() {
        // 使用PatientService获取所有患者
        Patient queryPatient = new Patient();
        return new ArrayList<>(patientService.selectAll(queryPatient));
    }
    
    /**
     * 获取患者的评估报告列表
     */
    public List<AssessmentReport> getReportsByPatientId(Integer patientId) {
        // 获取当前用户
        Account currentUser = TokenUtils.getCurrentUser();
        if (currentUser == null) {
            throw new CustomException(ResultCodeEnum.TOKEN_CHECK_ERROR);
        }
        
        // 验证权限
        String role = currentUser.getRole();
        if (!"admin".equals(role) && !"doctor".equals(role) && 
            (!"patient".equals(role) || !currentUser.getId().equals(patientId))) {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR.code, "无权查看该患者的评估报告");
        }
        
        return assessmentReportMapper.selectByPatientId(patientId);
    }
    
    /**
     * 获取医生负责的患者的评估报告列表
     */
    public List<AssessmentReport> getReportsByDoctorId(Integer doctorId) {
        // 获取当前用户
        Account currentUser = TokenUtils.getCurrentUser();
        if (currentUser == null) {
            throw new CustomException(ResultCodeEnum.TOKEN_CHECK_ERROR);
        }
        
        // 验证权限
        String role = currentUser.getRole();
        if (!"admin".equals(role) && 
            (!"doctor".equals(role) || !currentUser.getId().equals(doctorId))) {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR.code, "无权查看该医生负责的评估报告");
        }
        
        return assessmentReportMapper.selectByDoctorId(doctorId);
    }
    
    /**
     * 获取所有评估报告列表（管理员使用）
     */
    public List<AssessmentReport> getAllReports() {
        // 获取当前用户
        Account currentUser = TokenUtils.getCurrentUser();
        if (currentUser == null) {
            throw new CustomException(ResultCodeEnum.TOKEN_CHECK_ERROR);
        }
        
        // 验证权限
        if (!"admin".equals(currentUser.getRole())) {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR.code, "无权查看所有评估报告");
        }
        
        return assessmentReportMapper.selectAllReports();
    }
    
    /**
     * 添加医生批注
     */
    public void addDoctorComment(Integer reportId, String comment) {
        // 获取当前用户
        Account currentUser = TokenUtils.getCurrentUser();
        if (currentUser == null) {
            throw new CustomException(ResultCodeEnum.TOKEN_CHECK_ERROR);
        }
        
        // 验证权限
        if (!"doctor".equals(currentUser.getRole()) && !"admin".equals(currentUser.getRole())) {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR.code, "无权添加批注");
        }
        
        // 获取报告
        AssessmentReport report = assessmentReportMapper.selectById(reportId);
        if (report == null) {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR.code, "报告不存在");
        }
        
        // 更新批注
        report.setDoctorComment(comment);
        assessmentReportMapper.updateById(report);
    }
    
    /**
     * 更新报告状态为已读
     */
    public void markAsRead(Integer reportId) {
        // 获取当前用户
        Account currentUser = TokenUtils.getCurrentUser();
        if (currentUser == null) {
            throw new CustomException(ResultCodeEnum.TOKEN_CHECK_ERROR);
        }
        
        // 获取报告
        AssessmentReport report = assessmentReportMapper.selectById(reportId);
        if (report == null) {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR.code, "报告不存在");
        }
        
        // 验证权限
        if (!"admin".equals(currentUser.getRole()) && 
            !"doctor".equals(currentUser.getRole()) && 
            (!"patient".equals(currentUser.getRole()) || !currentUser.getId().equals(report.getPatientId()))) {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR.code, "无权操作该报告");
        }
        
        // 更新状态
        report.setStatus("已读");
        assessmentReportMapper.updateById(report);
    }
    
    /**
     * 通过ID获取单个报告
     * @param reportId 报告ID
     * @return 评估报告对象
     */
    public AssessmentReport getReportById(Integer reportId) {
        if (reportId == null) {
            throw new CustomException(ResultCodeEnum.PARAM_ERROR.code, "报告ID不能为空");
        }
        
        // 获取当前用户
        Account currentUser = TokenUtils.getCurrentUser();
        if (currentUser == null) {
            throw new CustomException(ResultCodeEnum.TOKEN_CHECK_ERROR);
        }
        
        // 查询报告
        AssessmentReport report = assessmentReportMapper.selectById(reportId);
        
        if (report == null) {
            return null;
        }
        
        // 权限检查
        String role = currentUser.getRole();
        Integer userId = currentUser.getId();
        
        // 管理员可以查看所有报告
        if ("admin".equals(role)) {
            return report;
        }
        
        // 医生可以查看自己负责的患者的报告
        if ("doctor".equals(role)) {
            List<AssessmentReport> doctorReports = getReportsByDoctorId(userId);
            boolean hasAccess = doctorReports.stream()
                    .anyMatch(r -> r.getId().equals(reportId));
            
            if (hasAccess) {
                return report;
            }
        }
        
        // 患者只能查看自己的报告
        if ("patient".equals(role) && userId.equals(report.getPatientId())) {
            return report;
        }
        
        // 无权限访问
        throw new CustomException(ResultCodeEnum.PARAM_ERROR.code, "无权访问该报告");
    }
} 