package cn.com.qmth.examcloud.core.questions.service.consumer;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.com.qmth.examcloud.api.commons.security.bean.User;
import cn.com.qmth.examcloud.commons.exception.StatusException;
import cn.com.qmth.examcloud.core.questions.base.BeanCopierUtil;
import cn.com.qmth.examcloud.core.questions.base.CommonUtils;
import cn.com.qmth.examcloud.core.questions.base.IoUtils;
import cn.com.qmth.examcloud.core.questions.base.Model;
import cn.com.qmth.examcloud.core.questions.base.multithread.Consumer;
import cn.com.qmth.examcloud.core.questions.dao.PaperDetailRepo;
import cn.com.qmth.examcloud.core.questions.dao.PaperDetailUnitRepo;
import cn.com.qmth.examcloud.core.questions.dao.PaperRepo;
import cn.com.qmth.examcloud.core.questions.dao.QuesRepo;
import cn.com.qmth.examcloud.core.questions.dao.entity.Paper;
import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetail;
import cn.com.qmth.examcloud.core.questions.dao.entity.PaperDetailUnit;
import cn.com.qmth.examcloud.core.questions.dao.entity.QuesOption;
import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
import cn.com.qmth.examcloud.core.questions.dao.entity.QuestionAudio;
import cn.com.qmth.examcloud.core.questions.service.QuestionAudioService;
import cn.com.qmth.examcloud.core.questions.service.UpYunService;
import cn.com.qmth.examcloud.core.questions.service.bean.CopyDataDto;
import cn.com.qmth.examcloud.core.questions.service.config.SysProperty;
import cn.com.qmth.examcloud.support.filestorage.FileStorageUtil;
import cn.com.qmth.examcloud.web.filestorage.FileStoragePathEnvInfo;
import cn.com.qmth.examcloud.web.filestorage.YunPathInfo;

@Scope("prototype")
@Service
public class CopyDataConsumer extends Consumer<CopyDataDto> {
	
	@Autowired
	private PaperRepo paperRepo;
	
	@Autowired
	private SysProperty sysProperty;
	
	@Autowired
	private PaperDetailRepo paperDetailRepo;
	
	@Autowired
	private PaperDetailUnitRepo paperDetailUnitRepo;
	
	@Autowired
	private QuestionAudioService questionAudioService;
	
	@Autowired
	private QuesRepo quesRepo;

    @Transactional
    @Override
    public int consume(CopyDataDto dto) {
    	clonePaper(dto);
        return 1;
    }

    private void clonePaper(CopyDataDto dto){
    	String paperId=dto.getPaperId();
    	User user=dto.getUser();
        if (StringUtils.isBlank(paperId)) {
            throw new StatusException("待复制的试卷ID不能为空！");
        }

        if (user == null) {
            throw new StatusException("当前用户信息不能为空！");
        }

        if (user.getRootOrgId() == null) {
            throw new StatusException("当前用户的顶级机构ID不能为空！");
        }

        Paper oldPaper = Model.of(paperRepo.findById(paperId));
        if (oldPaper == null) {
            throw new StatusException("待复制的试卷不存在！");
        }

        //复制原试卷的所有试题信息
        Map<PaperDetail, List<PaperDetailUnit>> detailMaps = this.copyPaperDetails(oldPaper, dto);

        //处理试题的音频(下载上传到云存储)
        try {
            this.dealQuestionAudios(detailMaps, user.getDisplayName());
        } catch (Exception e) {
            throw new StatusException("500","复制音频失败！",e);
        }

        //复制原试卷的信息
        Paper newPaper = this.copyPaper(oldPaper, dto);
        //保存新试卷
        paperRepo.save(newPaper);
        try {
            //保存新试卷的所有试题信息
            this.savePaperDetails(detailMaps, newPaper, user);
        } catch (Exception e) {
            throw new StatusException("500","克隆试卷失败！",e);
        }
    }

	
	private void savePaperDetails(Map<PaperDetail, List<PaperDetailUnit>> detailMaps, Paper newPaper, User user){
        if (StringUtils.isEmpty(newPaper.getId())) {
            throw new StatusException("试卷保存失败！");
        }
        for (Map.Entry<PaperDetail, List<PaperDetailUnit>> entry : detailMaps.entrySet()) {
            PaperDetail detail = entry.getKey();
            detail.setPaper(newPaper);
        }
        //批量保存大题
        paperDetailRepo.saveAll(detailMaps.keySet());
        List<PaperDetailUnit> newDetailUnits = new ArrayList<>();
        List<Question> newQuestions = new ArrayList<>();
        for (Map.Entry<PaperDetail, List<PaperDetailUnit>> entry : detailMaps.entrySet()) {
            PaperDetail detail = entry.getKey();
            List<PaperDetailUnit> detailUnits = entry.getValue();
            for (PaperDetailUnit detailUnit : detailUnits) {
                detailUnit.setPaper(newPaper);
                detailUnit.setPaperDetail(detail);
                newDetailUnits.add(detailUnit);
                newQuestions.add(detailUnit.getQuestion());
            }
        }
        //批量新增试题
        quesRepo.saveAll(newQuestions);

        for (Question question : newQuestions) {
            List<QuestionAudio> audioList = question.getAudioList();
            if (audioList != null && audioList.size() > 0) {
                for (QuestionAudio audio : audioList) {
                    audio.setQuestionId(question.getId());
                    questionAudioService.saveQuestionAudio(audio, user);
                }
                this.updateQuestionBody(question, audioList);
                //如果试题存在音频，则更新试题的音频信息
                quesRepo.save(question);
            }
        }

        //批量保存试题单元
        paperDetailUnitRepo.saveAll(newDetailUnits);
    }

    /**
     * 更新试题题干或选项中的音频存储ID
     */
    private void updateQuestionBody(Question question, List<QuestionAudio> audioList) {
        Map<String, String> audioMaps = new HashMap<>();
        for (QuestionAudio audio : audioList) {
            audioMaps.put(audio.getFileName(), audio.getId());
        }

        //在题干html片段中替换音频存储ID
        String body = question.getQuesBody();
        List<String> ids = CommonUtils.getTagANames(body);
        List<String> names = CommonUtils.getTagANames2(body);
        Map<String, String> oldBodyMap = new HashMap<>();
        for (int i = 0; i < ids.size(); i++) {
            oldBodyMap.put(names.get(i), ids.get(i));
        }
        for (String key : oldBodyMap.keySet()) {
            body = body.replace(oldBodyMap.get(key), audioMaps.get(key));
        }
        question.setQuesBody(body);

        if (question.getQuesOptions() == null || question.getQuesOptions().size() == 0) {
            return;
        }

        //替换选项中的音频存储ID
        for (QuesOption option : question.getQuesOptions()) {
            String newOptionBody = option.getOptionBody();
            List<String> optionIds = CommonUtils.getTagANames(newOptionBody);
            List<String> optionNames = CommonUtils.getTagANames2(newOptionBody);

            Map<String, String> oldOptionMap = new HashMap<>();
            for (int i = 0; i < optionIds.size(); i++) {
                oldOptionMap.put(optionNames.get(i), optionIds.get(i));
            }
            for (String key : oldOptionMap.keySet()) {
                newOptionBody = newOptionBody.replace(oldOptionMap.get(key), audioMaps.get(key));
            }
            option.setOptionBody(newOptionBody);
        }
    }


    /**
     * 处理试题的音频(下载上传到云存储)
     */
    private void dealQuestionAudios(Map<PaperDetail, List<PaperDetailUnit>> detailMaps, String userName){
//        UpYun upYun = upYunService.getInstance();
        String copyAudioPath = UpYunService.TEMP_FILE_EXP + File.separator + randomUUID();
        File copyAudioDir = new File(copyAudioPath);
        if (!copyAudioDir.exists()) {
            copyAudioDir.mkdirs();
        }
        for (Map.Entry<PaperDetail, List<PaperDetailUnit>> entry : detailMaps.entrySet()) {
            List<PaperDetailUnit> detailUnits = entry.getValue();
            for (PaperDetailUnit detailUnit : detailUnits) {
                Question question = detailUnit.getQuestion();
                List<QuestionAudio> audioList = question.getAudioList();
                if (audioList == null || audioList.size() == 0) {
                    continue;
                }
                for (QuestionAudio audio : audioList) {
                    //定义文件下载名称，并下载音频文件
                    String newAudioFileName = randomUUID() + "_" + audio.getFileName();
                    File audioFile = new File(copyAudioPath + File.separator + newAudioFileName);

//                    upYun.readFile(audio.getFileUrl(), audioFile);
                  //通用存储
                    FileStorageUtil.saveUrlAs(FileStorageUtil.realPath(audio.getFileUrl()), audioFile);

                    //重新上传新的音频文件
                    String newPath = sysProperty.getRadioUploadPath() + newAudioFileName;
                    try {
//                        upYun.writeFile(newPath, audioFile, true);
                        //通用存储
                		FileStoragePathEnvInfo env=new FileStoragePathEnvInfo();
                		env.setRelativePath(newPath);
                		YunPathInfo pi=FileStorageUtil.saveFile("audioFile", env, audioFile,null);
                        audio.setFileUrl(pi.getRelativePath());//设置新路径
                    } catch (Exception e) {
                        throw new StatusException("上传音频文件失败！");
                    } finally {
                        IoUtils.removeFile(audioFile);
                    }
                }
            }
        }

        IoUtils.removeFile(copyAudioDir);
    }

    /**
     * 复制试卷的所有试题信息
     */
    private Map<PaperDetail, List<PaperDetailUnit>> copyPaperDetails(Paper oldPaper, CopyDataDto dto){
        //批量查询原试卷的所有试题
        List<PaperDetailUnit> allDetailUnits = paperDetailUnitRepo.findByPaperOrderByNumber(oldPaper);
        if (allDetailUnits == null || allDetailUnits.size() == 0) {
            throw new StatusException("原试卷的试题不存在！");
        }
        //按大题有序封装对应的试题列表
        Map<PaperDetail, List<PaperDetailUnit>> oldDetailMaps = new TreeMap<>();
        for (PaperDetailUnit detailUnit : allDetailUnits) {
            PaperDetail detail = detailUnit.getPaperDetail();
            if (!oldDetailMaps.containsKey(detail)) {
                oldDetailMaps.put(detail, new ArrayList<>());
            }
            List<PaperDetailUnit> detailUnits = oldDetailMaps.get(detail);
            detailUnits.add(detailUnit);
        }
        //开始复制
        Map<PaperDetail, List<PaperDetailUnit>> detailMaps = new TreeMap<>();
        for (Map.Entry<PaperDetail, List<PaperDetailUnit>> entry : oldDetailMaps.entrySet()) {
            //复制大题信息
            PaperDetail oldPaperDetail = entry.getKey();
            PaperDetail paperDetail = this.copyPaperDetail(oldPaperDetail, dto);
            //复制大题下的所有试题单元
            List<PaperDetailUnit> oldDetailUnits = entry.getValue();
            List<PaperDetailUnit> detailUnits = new ArrayList<>();
            for (PaperDetailUnit oldDetailUnit : oldDetailUnits) {
                PaperDetailUnit detailUnit = this.copyPaperDetailUnit(oldDetailUnit, dto);
                detailUnits.add(detailUnit);
            }
            detailMaps.put(paperDetail, detailUnits);
        }
        return detailMaps;
    }

    /**
     * 复制试题的音频
     */
    private QuestionAudio copyQuestionAudio(QuestionAudio oldAudio, CopyDataDto dto) {
        QuestionAudio audio = new QuestionAudio();
        audio.setId(null);
        audio.setQuestionId(null);
        audio.setFileUrl(oldAudio.getFileUrl());
        audio.setFileName(oldAudio.getFileName());
        audio.setFileSuffixes(oldAudio.getFileSuffixes());
        audio.setCreateTime(new Date());
        audio.setCreateUser(dto.getUser().getDisplayName());
        audio.setOrgId(dto.getToRootOrgId());
        audio.setCreationBy(dto.getUser().getUserId());
        audio.setUpdateBy(dto.getUser().getUserId());
        return audio;
    }

    /**
     * 复制试题信息
     */
    private Question copyQuestion(Question oldQuestion,CopyDataDto dto) {
        Question question = BeanCopierUtil.copyProperties(oldQuestion, Question.class);
        question.setId(null);
        question.getCourse().setId(getCourseId(dto.getCourses(), question.getCourse().getCode()).toString());
        question.getCourse().setOrgId(dto.getToRootOrgId().toString());
        question.setOrgId(dto.getToRootOrgId().toString());
        question.setQuesProperties(null);
        question.setCreateTime(CommonUtils.getCurDateTime());
        question.setUpdateTime(CommonUtils.getCurDateTime());
        question.setPropertyGroup(null);
        question.setCreationBy(dto.getUser().getUserId());
        question.setUpdateBy(dto.getUser().getUserId());
        if (oldQuestion.getHasAudio() == null || !oldQuestion.getHasAudio()) {
            question.setHasAudio(false);
            return question;
        }
        //复制试题的音频
        List<QuestionAudio> audioList = questionAudioService.findQuestionAudiosByQuestionId(oldQuestion.getId());
        if (audioList != null && audioList.size() > 0) {
            for (QuestionAudio oldAudio : audioList) {
                QuestionAudio audio = this.copyQuestionAudio(oldAudio, dto);
                question.addAudio(audio);
            }
        }
        return question;
    }

    /**
     * 复制试题单元信息
     */
    private PaperDetailUnit copyPaperDetailUnit(PaperDetailUnit oldDetailUnit,CopyDataDto dto){
        Question oldQuestion = oldDetailUnit.getQuestion();
        if (oldQuestion == null) {
            throw new StatusException("原试题详细信息不存在！");
        }
        PaperDetailUnit detailUnit = new PaperDetailUnit();
        detailUnit.setNumber(oldDetailUnit.getNumber());
        detailUnit.setScore(oldDetailUnit.getScore());
        detailUnit.setSubScoreList(oldDetailUnit.getSubScoreList());
        detailUnit.setQuestionType(oldDetailUnit.getQuestionType());
        detailUnit.setOptionOrder(oldDetailUnit.getOptionOrder());
        detailUnit.setPaperType(oldDetailUnit.getPaperType());
        detailUnit.setCreator(dto.getUser().getDisplayName());
        detailUnit.setCreateTime(CommonUtils.getCurDateTime());
        detailUnit.setOrgId(dto.getToRootOrgId());
        detailUnit.setCreationBy(dto.getUser().getUserId());
        detailUnit.setUpdateBy(dto.getUser().getUserId());
        detailUnit.setPaper(null);
        detailUnit.setPaperDetail(null);
        //复制试题信息
        Question question = this.copyQuestion(oldQuestion, dto);
        detailUnit.setQuestion(question);
        return detailUnit;
    }

    /**
     * 复制大题信息
     */
    private PaperDetail copyPaperDetail(PaperDetail oldPaperDetail, CopyDataDto dto) {
        PaperDetail paperDetail = new PaperDetail();
        paperDetail.setNumber(oldPaperDetail.getNumber());
        paperDetail.setName(oldPaperDetail.getName());
        paperDetail.setTitle(oldPaperDetail.getTitle());
        paperDetail.setScore(oldPaperDetail.getScore());
        paperDetail.setUnitCount(oldPaperDetail.getUnitCount());
        paperDetail.setCreator(dto.getUser().getDisplayName());
        paperDetail.setCreateTime(CommonUtils.getCurDateTime());
        paperDetail.setPaper(null);
        paperDetail.setOrgId(dto.getToRootOrgId());
        paperDetail.setCreationBy(dto.getUser().getUserId());
        paperDetail.setUpdateBy(dto.getUser().getUserId());
        return paperDetail;
    }

    /**
     * 复制试卷信息
     */
    private Paper copyPaper(Paper oldPaper, CopyDataDto dto) {
        Paper newPaper = BeanCopierUtil.copyProperties(oldPaper, Paper.class);
        newPaper.getCourse().setId(getCourseId(dto.getCourses(), newPaper.getCourse().getCode()).toString());
        newPaper.getCourse().setOrgId(dto.getToRootOrgId().toString());
        newPaper.setOrgId(String.valueOf(dto.getToRootOrgId()));
        newPaper.setCreateTime(CommonUtils.getCurDateTime());
        newPaper.setLastModifyName(dto.getUser().getDisplayName());
        newPaper.setCreator(dto.getUser().getDisplayName());
        newPaper.setCreationBy(dto.getUser().getUserId());
        newPaper.setUpdateBy(dto.getUser().getUserId());
        newPaper.setId(null);
        return newPaper;
    }
    private String randomUUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }
	private Long getCourseId(Map<String,Long> courses,String code) {
		Long id=courses.get(code);
		if(id==null) {
			throw new StatusException("没有课程信息code="+code);
		}
		return id;
	}
}
