package com.ruoyi.web.service;

import com.alibaba.fastjson.JSONArray;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ruoyi.common.core.content.VistorContextHolder;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.enums.UserRegStatus;
import com.ruoyi.common.exception.CustomException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.ruoyi.dz.domain.DzCards;
import com.ruoyi.dz.service.IDzCardsService;
import com.ruoyi.enums.CardTimeStatus;
import com.ruoyi.enums.UserTypeEnum;
import com.ruoyi.learn.domain.LearnKnowledgeCourse;
import com.ruoyi.learn.domain.LearnKnowledgeTree;
import com.ruoyi.learn.domain.LearnPaper;
import com.ruoyi.learn.domain.LearnQuestions;
import com.ruoyi.learn.service.ILearnPaperService;
import com.ruoyi.learn.service.ILearnQuestionsService;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.utils.downloadpaper.DownloadPaperUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class CommService {
    private final ISysConfigService configService;
    private final IDzCardsService cardsService;

    @Autowired
    ILearnPaperService paperService;
    @Autowired
    ILearnQuestionsService learnQuestionsService;

    public CommService(ISysConfigService configService, IDzCardsService cardsService) {
        this.configService = configService;
        this.cardsService = cardsService;
    }


    // 检查初始密码是否提醒修改
    public boolean initPasswordIsModify(Date pwdUpdateDate)
    {
        Integer initPasswordModify = Convert.toInt(configService.selectConfigByKey("sys.account.initPasswordModify"));
        return initPasswordModify != null && initPasswordModify == 1 && pwdUpdateDate == null;
    }

    // 检查密码是否过期
    public boolean passwordIsExpiration(Date pwdUpdateDate)
    {
        Integer passwordValidateDays = Convert.toInt(configService.selectConfigByKey("sys.account.passwordValidateDays"));
        if (passwordValidateDays != null && passwordValidateDays > 0)
        {
            if (StringUtils.isNull(pwdUpdateDate))
            {
                // 如果从未修改过初始密码，直接提醒过期
                return true;
            }
            Date nowDate = DateUtils.getNowDate();
            return DateUtils.differentDaysByMillisecond(nowDate, pwdUpdateDate) > passwordValidateDays;
        }
        return false;
    }

    public void requireVip() {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        if (!UserRegStatus.Student.equals(user.getRegStatus()) || null == user.getCardId()) {
            if (UserTypeEnum.isCard(user.getUserType())) {
                throw new CustomException("没有权限，请开通VIP", 405);
            }
            return;
        }
        DzCards card = cardsService.selectDzCardsByCardId(user.getCardId());
        Date nowDate = Date.from(LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant());
        if (null == card || !CardTimeStatus.Valid.getVal().equals(card.getTimeStatus()) || (null != card.getOutDate() && card.getOutDate().getTime() < nowDate.getTime())) {
            throw new CustomException("没有权限，请开通VIP", 405);
        }
    }

    public List<LearnTeacherService.TreeNode> buildTree(List<LearnKnowledgeTree> ktList, Set<Long> knowledgeIdSet, Map<Long, Integer[]> knowCountMap) {
        List<LearnTeacherService.TreeNode> treeNodeList = Lists.newArrayList();
        Map<Long, LearnTeacherService.TreeNode> teMap = Maps.newHashMap();
        Integer[] counts;
        for(LearnKnowledgeTree kt : ktList) {
            LearnTeacherService.TreeNode tn;
            if(null != knowCountMap && null != (counts = knowCountMap.get(kt.getId()))) {
                tn = new LearnTeacherService.TreeNode(kt.getId(), kt.getName(),kt.getSubjectId(),  counts);
            } else {
                tn = new LearnTeacherService.TreeNode(kt.getId(), kt.getName(),kt.getSubjectId(),  null);
            }
            teMap.put(kt.getId(), tn);
        }
        for(LearnKnowledgeTree kt : ktList) {
            if(null == kt.getPid()) {
                treeNodeList.add(teMap.get(kt.getId()));
                continue;
            }
            LearnTeacherService.TreeNode parent = teMap.get(kt.getPid());
            LearnTeacherService.TreeNode node = teMap.get(kt.getId());
            if(null != node.getQuestionCount()) {
                if(null == parent) {
                    continue;
                }
                parent.setQuestionCount(parent.getQuestionCount() + node.getQuestionCount());
                parent.setFinishedCount(parent.getFinishedCount() + node.getFinishedCount());
                parent.setRightCount(parent.getRightCount() + node.getRightCount());
                parent.calcRatio();
            }
            parent.getChildren().add(node);
        }
        if(!CollectionUtils.isEmpty(knowledgeIdSet)) {
            List<LearnTeacherService.TreeNode> childList;
            List<LearnTeacherService.TreeNode> rootList = Lists.newArrayList();
            for(LearnTeacherService.TreeNode tn : treeNodeList) {
                if(knowledgeIdSet.contains(tn.getId())) {
                    rootList.add(tn);
                } else if(!(childList = tn.getChildren().stream().filter(t -> knowledgeIdSet.contains(t.getId())).collect(Collectors.toList())).isEmpty()) {
                    tn.setChildren(childList);
                    rootList.add(tn);
                }
            }
            return rootList;
        }
        return treeNodeList;
    }

    public List<LearnTeacherService.TreeNode> buildCourseKnowledgeTree(List<LearnKnowledgeCourse> ktList, Map<Long, Integer[]> knowCountMap) {
        List<LearnTeacherService.TreeNode> treeNodeList = Lists.newArrayList();
        Map<Long, LearnTeacherService.TreeNode> teMap = Maps.newHashMap();
        Integer[] counts;
        for(LearnKnowledgeCourse kt : ktList) {
            LearnTeacherService.TreeNode tn;
            if(null != knowCountMap && null != (counts = knowCountMap.get(kt.getId()))) {
                tn = new LearnTeacherService.TreeNode(kt.getId(), kt.getName(),null,  counts);
            } else {
                tn = new LearnTeacherService.TreeNode(kt.getId(), kt.getName(),null,  null);
            }
            teMap.put(kt.getId(), tn);
        }
        for(LearnKnowledgeCourse kt : ktList) {
            if(null == kt.getPid()) {
                treeNodeList.add(teMap.get(kt.getId()));
                continue;
            }
            LearnTeacherService.TreeNode parent = teMap.get(kt.getPid());
            LearnTeacherService.TreeNode node = teMap.get(kt.getId());
            if(null != node.getQuestionCount()) {
                parent.setQuestionCount(parent.getQuestionCount() + node.getQuestionCount());
                parent.setFinishedCount(parent.getFinishedCount() + node.getFinishedCount());
                parent.setRightCount(parent.getRightCount() + node.getRightCount());
                parent.calcRatio();
            }
            parent.getChildren().add(node);
        }
        return treeNodeList;
    }
    public String getLocation(){
        return getLocation(null);
    }
    public String getLocation(String location){
        if(org.apache.commons.lang3.StringUtils.isBlank(location)) {
            location = VistorContextHolder.getLocation();
        }
        if (org.apache.commons.lang3.StringUtils.isBlank(location)) {
            location = "湖南";
        }
        return location;
    }

    /**
     * 下载试卷
     * @param response
     * @param paperId
     */
    public void download(HttpServletResponse response, Long paperId){
        try {
            LearnPaper papers = paperService.selectLearnPaperById(paperId);
            List<LearnQuestions> questions = learnQuestionsService.selectQuestionByPaperId(paperId);
            byte[] data = DownloadPaperUtils.download(papers.getPaperName(), questions);

            response.setHeader("Pragma", "No-cache");
            response.setHeader("Cache-Control", "No-cache");
            response.setHeader("Expires", "0");
            response.setHeader("Content-Disposition",  String.format("attachment; filename=\"%s\"", new String((papers.getPaperName() + ".docx").getBytes("utf-8"), "ISO-8859-1")));
            response.setHeader("Content-Type", "application/octet-stream");
            IOUtils.write(data, response.getOutputStream());
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    public void downloadRemote(HttpServletResponse response, Long paperId,String url) {
        try {
            // 获取试卷信息
            LearnPaper paper = paperService.selectLearnPaperById(paperId);
            if (paper == null) {
                throw new RuntimeException("试卷不存在");
            }

            // 获取题目列表
            List<LearnQuestions> questions = learnQuestionsService.selectQuestionByPaperId(paperId);

            // 将题目列表转换为 JSON 字符串
            String quesJson = JSONArray.toJSONString(questions);

            // 远程服务器地址
            String remoteUrl = (StringUtils.isEmpty(url)?"https://www.dz1kt.com/prod-api":url)+"/learn/paper/downloadPaper";

            // 构建请求参数
            String params = "paperName=" + java.net.URLEncoder.encode(paper.getPaperName(), StandardCharsets.UTF_8.toString())
                    + "&ques=" + java.net.URLEncoder.encode(quesJson, StandardCharsets.UTF_8.toString());

            // 设置响应头
            response.setHeader("Pragma", "No-cache");
            response.setHeader("Cache-Control", "No-cache");
            response.setHeader("Expires", "0");
            response.setHeader("Content-Disposition", String.format("attachment; filename=\"%s\"",
                    new String((paper.getPaperName() + ".docx").getBytes("utf-8"), "ISO-8859-1")));
            response.setHeader("Content-Type", "application/octet-stream");

            // 调用远程服务器并将响应流写入到本地响应
            HttpUtils.sendGetStream(remoteUrl, params, response.getOutputStream());
        } catch (Exception e) {
            throw new RuntimeException("下载失败: " + e.getMessage(), e);
        }
    }

    /**
     * 通用：下载试卷（外部传入数据），不依赖本地数据
     * @param response
     * @param paperName
     * @param questions
     */
    public void download(HttpServletResponse response, String paperName,List<LearnQuestions> questions){
        try {
            byte[] data = DownloadPaperUtils.download(paperName, questions);

            response.setHeader("Pragma", "No-cache");
            response.setHeader("Cache-Control", "No-cache");
            response.setHeader("Expires", "0");
            response.setHeader("Content-Disposition",  String.format("attachment; filename=\"%s\"", new String((paperName + ".docx").getBytes("utf-8"), "ISO-8859-1")));
            response.setHeader("Content-Type", "application/octet-stream");
            IOUtils.write(data, response.getOutputStream());
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }


}
