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

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import cn.com.qmth.examcloud.api.commons.security.bean.User;
import cn.com.qmth.examcloud.commons.exception.StatusException;
import cn.com.qmth.examcloud.core.basic.api.CourseCloudService;
import cn.com.qmth.examcloud.core.basic.api.request.GetCourseReq;
import cn.com.qmth.examcloud.core.basic.api.response.GetCourseResp;
import cn.com.qmth.examcloud.core.questions.base.Model;
import cn.com.qmth.examcloud.core.questions.base.converter.utils.FileUtil;
import cn.com.qmth.examcloud.core.questions.base.enums.PaperStatus;
import cn.com.qmth.examcloud.core.questions.base.enums.PaperType;
import cn.com.qmth.examcloud.core.questions.base.question.enums.QuesStructType;
import cn.com.qmth.examcloud.core.questions.dao.CoursePropertyRepo;
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.PropertyRepo;
import cn.com.qmth.examcloud.core.questions.dao.QuesRepo;
import cn.com.qmth.examcloud.core.questions.dao.QuesTypeNameRepo;
import cn.com.qmth.examcloud.core.questions.dao.entity.Course;
import cn.com.qmth.examcloud.core.questions.dao.entity.CourseProperty;
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.Property;
import cn.com.qmth.examcloud.core.questions.dao.entity.QuesOption;
import cn.com.qmth.examcloud.core.questions.dao.entity.QuesProperty;
import cn.com.qmth.examcloud.core.questions.dao.entity.QuesTypeName;
import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
import cn.com.qmth.examcloud.web.config.SystemProperties;

@Component
public class YunkaiService {
	@Autowired
	private CoursePropertyRepo coursePropertyRepo;
	@Autowired
	private CourseCloudService courseCloudService;
	@Autowired
	private PaperRepo paperRepo;
	@Autowired
	private PaperDetailRepo paperDetailRepo;

	@Autowired
	private PaperDetailUnitRepo paperDetailUnitRepo;
	@Autowired
	private MongoTemplate mongoTemplate;
	
	@Autowired
	private QuesRepo quesRepo;
	@Autowired
	private QuesTypeNameRepo quesTypeNameRepo;
	@Autowired
	private SystemProperties systemProperties;

	@Autowired
	private PropertyRepo propertyRepo;
	
	private Map<String,String> allProperty(String coursePropertyId){
		List<Property> list=propertyRepo.findByCoursePropertyIdOrderByNumber(coursePropertyId);
		Map<String,String> map=new HashMap<>();
		if(CollectionUtils.isNotEmpty(list)) {
			for(Property p:list) {
				if(StringUtils.isNotBlank(p.getFromId())) {
					map.put(p.getFromId(), p.getId());
				}
			}
		}
		return map; 
	}

	private void savePropOneCourse(User user, File zfile, Long rootOrgId, String courseCode, String batch) {
		GetCourseReq req = new GetCourseReq();
		req.setRootOrgId(rootOrgId);
		req.setCode(courseCode);
		GetCourseResp res = courseCloudService.getCourse(req);

		CourseProperty cp =coursePropertyRepo.findByOrgIdAndCourseIdAndBatch(rootOrgId, res.getCourseBean().getId(),batch);
		Map<String,String> allProperty=new HashMap<>();
		if(cp==null) {
			cp= new CourseProperty();
			cp.setCourseCode(courseCode);
			cp.setCourseId(res.getCourseBean().getId());
			cp.setCourseName(res.getCourseBean().getName());
			cp.setEnable(true);
			cp.setOrgId(rootOrgId);
			cp.setName(res.getCourseBean().getName() + "课程属性" + batch);
			cp.setBatch(batch);
			coursePropertyRepo.save(cp);
		}else {
			allProperty=allProperty(cp.getId());
		}
		
		String json;
		try {
			json = FileUtils.readFileToString(zfile, "utf-8");
		} catch (IOException e) {
			throw new StatusException("500", "文件读取出错", e);
		}
		List<PropertyDto> pds = JSON.parseArray(json, PropertyDto.class);
		int num = 0;
		for (PropertyDto pd : pds) {
			num++;
			Property p = new Property();
			if(!allProperty.keySet().contains(pd.getId().toString())) {
				p.setCode(pd.getName());
				p.setCoursePropertyId(cp.getId());
				p.setName(pd.getName());
				p.setNumber(num);
				p.setOrgId(rootOrgId);
				p.setParentId("0");
				p.setFromId(pd.getId().toString());
				p.setBatch(batch);
				propertyRepo.save(p);
			}else {
				p.setId(allProperty.get(pd.getId().toString()));
			}
			if (CollectionUtils.isNotEmpty(pd.getSubPropertyDto())) {
				int subnum = 0;
				List<Property> ps = new ArrayList<>();
				for (PropertyDto subpd : pd.getSubPropertyDto()) {
					subnum++;
					if(!allProperty.keySet().contains(subpd.getId().toString())) {
						Property subp = new Property();
						subp.setCode(subpd.getName());
						subp.setCoursePropertyId(cp.getId());
						subp.setName(subpd.getName());
						subp.setNumber(subnum);
						subp.setOrgId(rootOrgId);
						subp.setParentId(p.getId());
						subp.setFromId(subpd.getId().toString());
						subp.setBatch(batch);
						ps.add(subp);
					}
				}
				if(ps.size()>0) {
					propertyRepo.saveAll(ps);
				}
			}
		}
	}
	
	@Transactional
	public void saveProp(User user, MultipartFile dataFile, Long rootOrgId, List<String> courseCodes, String batch) {
		String tempDir = systemProperties.getTempDataDir();
		String dir = tempDir + File.separator + UUID.randomUUID() + File.separator;
		try {
			File dfile = new File(dir);
			dfile.mkdirs();
			File zfile = new File(dir + dataFile.getOriginalFilename());
			zfile.createNewFile();
			dataFile.transferTo(zfile);
			for (String courseCode : courseCodes) {
				savePropOneCourse(user, zfile, rootOrgId, courseCode, batch);
			}
		} catch (IOException e) {
			throw new StatusException("500", "出错", e);
		} finally {
			FileUtil.deleteFolder(dir);
		}
	}

	@Transactional
	public void propClear(Long rootOrgId, String batch) {
		coursePropertyRepo.deleteByOrgIdAndBatch(rootOrgId, batch);
		propertyRepo.deleteByOrgIdAndBatch(rootOrgId, batch);
	}

	@Transactional
	public void importYunkaiPaper(YunkaiImportPaperParam p) {
		String tempDir = systemProperties.getTempDataDir();
		String dir = tempDir + File.separator + UUID.randomUUID() + File.separator;
		try {
			File dfile = new File(dir);
			dfile.mkdirs();
			File zfile = new File(dir + p.getDataFile().getOriginalFilename());
			zfile.createNewFile();
			p.getDataFile().transferTo(zfile);
			FileUtil.unZip(dfile, zfile);
			resolvingFile(dfile, p);
		} catch (IOException e) {
			throw new StatusException("500", "出错", e);
		} finally {
			FileUtil.deleteFolder(dir);
		}
	}

	private void getPaperFile(File file, List<File> ret) {
		if (file.isFile()) {
			if (file.getName().endsWith(".json")) {
				ret.add(file);
			}
			return;
		} else {
			for (File paperDir : file.listFiles()) {
				getPaperFile(paperDir, ret);
			}
		}

	}

	private void resolvingFile(File file, YunkaiImportPaperParam p) {
		List<File> files = new ArrayList<>();
		getPaperFile(file, files);
		for (String courseCode : p.getCourseCodes()) {
			GetCourseReq req = new GetCourseReq();
			req.setRootOrgId(p.getRootOrgId());
			req.setCode(courseCode);
			GetCourseResp res = courseCloudService.getCourse(req);
			Course c = new Course();
			c.setId(res.getCourseBean().getId().toString());
			c.setCode(res.getCourseBean().getCode());
			c.setEnable(res.getCourseBean().getEnable().toString());
			c.setLevel(res.getCourseBean().getLevel());
			c.setName(res.getCourseBean().getName());
			c.setOrgId(res.getCourseBean().getRootOrgId().toString());
			p.setCourse(c);
			CourseProperty cp =coursePropertyRepo.findByOrgIdAndCourseIdAndBatch(p.getRootOrgId(),res.getCourseBean().getId(),p.getBatch());
			p.setCourseProperty(cp);
			for (File paperFile : files) {
				KdPaper kpaper = JSONObject.parseObject(FileUtil.readFileContent(paperFile), KdPaper.class);
				kpaper.setCourseCode(courseCode);
				savePaper(kpaper, p);
			}
		}
	}

	private void savePaper(KdPaper kpaper, YunkaiImportPaperParam p) {
		int questionNum = 0;
		Paper paper = initPaper(kpaper, p);
		checkPaperName(paper.getOrgId(),paper.getCourse().getCode(), paper.getName());
		paper.setDifficultyDegree(0.5);
		// 定义大题集合
		List<PaperDetail> paperDetails = new ArrayList<>();
		// 定义小题集合
		List<PaperDetailUnit> paperDetailUnits = new ArrayList<>();
		List<Question> questions = new ArrayList<Question>();
		for (int i = 0; i < kpaper.getDetails().size(); i++) {
			KdDetail de = kpaper.getDetails().get(i);
			de.setNumber(i + 1);
			PaperDetail paperDetail = initPaperDetail(de, paper);
			paperDetails.add(paperDetail);
			for (KdQuestion que : de.getQuestions()) {
				questionNum++;
				Question question = initQuestion(que, p);
				questions.add(question);
				PaperDetailUnit paperDetailUnit = initPaperDetailUnit(paper, paperDetail, question, questionNum,
						p.getUser());
				paperDetailUnits.add(paperDetailUnit);
			}
		}

		quesRepo.saveAll(questions);
		paperRepo.save(paper);
		paperDetailRepo.saveAll(paperDetails);
		paperDetailUnitRepo.saveAll(paperDetailUnits);
		if (paperDetailUnits.size() > 0) {
			saveQuesTypeName(paperDetailUnits);
		}
//		paperService.formatPaper(paper, p.getUser());
	}

	private void saveQuesTypeName(List<PaperDetailUnit> detailUnitList) {

		for (PaperDetailUnit paperDetailUnit : detailUnitList) {
			String orgId = paperDetailUnit.getPaper().getOrgId();
			String courseNo = paperDetailUnit.getPaper().getCourseNo();
			QuesStructType questionType = paperDetailUnit.getQuestionType();
			String detailName = paperDetailUnit.getPaperDetail().getName();
			List<QuesTypeName> quesTypeNames = quesTypeNameRepo.findQuesName(orgId, courseNo, questionType);
			if (quesTypeNames != null && quesTypeNames.size() > 0) {
				QuesTypeName quesTypeName = quesTypeNames.get(0);
				List<String> quesNames = quesTypeName.getQuesNames();
				if (quesNames != null && quesNames.size() > 0) {
					if (quesNames.contains(detailName)) {
						continue;
					} else {
						quesNames.add(detailName);
					}
				} else {
					quesNames = new ArrayList<>();
					quesNames.add(detailName);
				}
				quesTypeName.setQuesNames(quesNames);
				quesTypeNameRepo.save(quesTypeName);
			} else {
				QuesTypeName quesTypeName = new QuesTypeName();
				List<String> quesNames = new ArrayList<>();
				quesNames.add(detailName);
				quesTypeName.setOrgId(orgId);
				quesTypeName.setCourseNo(courseNo);
				quesTypeName.setQuestionType(questionType);
				quesTypeName.setQuesNames(quesNames);
				quesTypeNameRepo.save(quesTypeName);
			}
		}
	}

	private Paper initPaper(KdPaper kpaper, YunkaiImportPaperParam p) {
		int unitCount = 0;
		for (KdDetail de : kpaper.getDetails()) {
			unitCount = unitCount + de.getQuestions().size();
		}
		Paper paper = new Paper();
		paper.setName(kpaper.getName());
		paper.setTitle(kpaper.getName());
		paper.setPaperType(PaperType.IMPORT);
		paper.setPaperStatus(PaperStatus.DRAFT);
		paper.setOrgId(p.getRootOrgId().toString());
		paper.setCreator(p.getUser().getDisplayName());
		paper.setTotalScore(unitCount + 0.0);
		paper.setCourse(p.getCourse());
		paper.setCourseName(p.getCourse().getName());
		paper.setCourseNo(p.getCourse().getCode());
		paper.setCreateTime(getCurDateTime());
		paper.setPaperDetailCount(kpaper.getDetails().size());
		paper.setCreationBy(p.getUser().getUserId());
		paper.setCreationDate(new Date());
		paper.setUnitCount(unitCount);
		return paper;
	}

	private String getCurDateTime() {
		return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
	}

	private PaperDetail initPaperDetail(KdDetail de, Paper paper) {
		PaperDetail paperDetail = new PaperDetail();
		if (de.getQuestions() != null && de.getQuestions().size() > 0) {
			paperDetail.setPaper(paper);
			paperDetail.setNumber(de.getNumber());
			paperDetail.setName(de.getName());
			paperDetail.setScore(de.getQuestions().size() + 0.0);
			paperDetail.setUnitCount(de.getQuestions().size());
			paperDetail.setCreator(paper.getCreator());
			paperDetail.setCreateTime(getCurDateTime());
			paperDetail.setCreationBy(paper.getCreationBy());
			paperDetail.setCreationDate(new Date());
		}
		return paperDetail;
	}

	private Question initQuestion(KdQuestion que, YunkaiImportPaperParam p) {
		Question question = new Question();
		question.setFromId(que.getId().toString());
		question.setCreateTime(getCurDateTime());
		question.setScore(1.0);
		question.setCourse(p.getCourse());
		question.setOrgId(p.getRootOrgId().toString());
		question.setHasAudio(false);
		if (que.getDifficulty() == null) {
			question.setDifficulty("易");
			question.setDifficultyDegree(0.5);
		} else {
			question.setDifficulty(que.getDifficulty().getDesc());
			question.setDifficultyDegree(que.getDifficulty().getType());
		}
		question.setPublicity(true);
		question.setCreationBy(p.getUser().getUserId());
		question.setCreationDate(new Date());
		question.setCreateTime(getCurDateTime());
		// 按试题分类初始化题干，答案，选项
		initQuestionInfo(question, que);
		initQuestionProp(question, que, p);
		return question;
	}

	private void initQuestionProp(Question question, KdQuestion que, YunkaiImportPaperParam p) {
		if (CollectionUtils.isEmpty(que.getPropIds())) {
			return;
		}
		List<QuesProperty> quesProperties = new ArrayList<>();
		for (Long id : que.getPropIds()) {
			Property prop = propertyRepo.findByCoursePropertyIdAndFromId(p.getCourseProperty().getId(), id.toString());
			QuesProperty qp = new QuesProperty();
			quesProperties.add(qp);
			qp.setCoursePropertyName(p.getCourseProperty().getName());
			if ("0".equals(prop.getParentId())) {
				qp.setFirstProperty(prop);
			} else {
				Property fprop = Model.of(propertyRepo.findById(prop.getParentId()));
				qp.setFirstProperty(fprop);
				qp.setSecondProperty(prop);
			}
		}
		question.setQuesProperties(quesProperties);
	}

	private void initQuestionInfo(Question question, KdQuestion que) {
		// 单选题
		if (YunkaiQuesStructType.DANXUAN.equals(que.getQst())) {
			String quesBody = que.getBody();
			question.setQuesBody(quesBody);
			question.setQuestionType(QuesStructType.SINGLE_ANSWER_QUESTION);
			List<QuesOption> quesOptions = new ArrayList<QuesOption>();
			List<KdQuesOption> options = que.getOptions();
			Integer answerNumber = null;
			if (options != null && options.size() > 0) {
				int number = 1;
				short isCorrect = 0;
				for (KdQuesOption testOption : options) {
					if (testOption.getSelect()) {
						isCorrect = 1;
						answerNumber = number;
					} else {
						isCorrect = 0;
					}
					QuesOption quesOption = initQuesOption(testOption, isCorrect);
					quesOptions.add(quesOption);
					number++;
				}
			}
			question.setQuesOptions(quesOptions);
			if (answerNumber != null) {
				char c1 = (char) (answerNumber + 64);
				question.setQuesAnswer(String.valueOf(c1));
			}
		} else if (YunkaiQuesStructType.DUOXUAN.equals(que.getQst())
				|| YunkaiQuesStructType.BUDINGXIANG.equals(que.getQst())) {
			String quesBody = que.getBody();
			question.setQuesBody(quesBody);
			question.setQuestionType(QuesStructType.MULTIPLE_ANSWER_QUESTION);
			List<QuesOption> quesOptions = new ArrayList<QuesOption>();
			List<KdQuesOption> options = que.getOptions();
			List<Integer> answerNumbers = new ArrayList<Integer>();
			if (options != null && options.size() > 0) {
				int number = 1;
				short isCorrect = 0;
				for (KdQuesOption testOption : options) {
					if (testOption.getSelect()) {
						isCorrect = 1;
						answerNumbers.add(number);
					} else {
						isCorrect = 0;
					}
					QuesOption quesOption = initQuesOption(testOption, isCorrect);
					quesOptions.add(quesOption);
					number++;
				}
			}
			question.setQuesOptions(quesOptions);
			if (answerNumbers != null && answerNumbers.size() > 0) {
				String answers = "";
				for (Integer number : answerNumbers) {
					char c1 = (char) (number + 64);
					if (StringUtils.isBlank(answers)) {
						answers = String.valueOf(c1);
					} else {
						answers = answers + "," + String.valueOf(c1);
					}
				}
				question.setQuesAnswer(answers);
			}
		} else if (YunkaiQuesStructType.PANDUAN.equals(que.getQst())) {
			String quesBody = que.getBody();
			question.setQuesBody(quesBody);
			question.setQuestionType(QuesStructType.BOOL_ANSWER_QUESTION);
			String answer = que.getAnswer();
			question.setQuesAnswer(answer);
		} else if (YunkaiQuesStructType.TIANKONGTI.equals(que.getQst())) {
			String quesBody = que.getBody();
			question.setQuesBody(quesBody);
			question.setQuestionType(QuesStructType.FILL_BLANK_QUESTION);
			String answer = que.getAnswer();
			question.setQuesAnswer(answer);
		} else {// 全是问答题
			String quesBody = que.getBody();
			question.setQuesBody(quesBody);
			question.setQuestionType(QuesStructType.TEXT_ANSWER_QUESTION);
			String answer = que.getAnswer();
			question.setQuesAnswer(answer);
		}
	}

	private QuesOption initQuesOption(KdQuesOption testOption, short isCorrect) {
		QuesOption quesOption = new QuesOption();
		quesOption.setNumber(testOption.getNumber().toString());
		quesOption.setIsCorrect(isCorrect);
		String optionBody = testOption.getBody();
		quesOption.setOptionBody(optionBody);
		return quesOption;
	}

	private PaperDetailUnit initPaperDetailUnit(Paper paper, PaperDetail paperDetail, Question question,
			int questionNum, User user) {
		PaperDetailUnit paperDetailUnit = new PaperDetailUnit();
		paperDetailUnit.setPaper(paper);
		paperDetailUnit.setNumber(questionNum);
		paperDetailUnit.setScore(1.0);
		paperDetailUnit.setPaperDetail(paperDetail);
		paperDetailUnit.setQuestionType(question.getQuestionType());
		paperDetailUnit.setCreator(user.getDisplayName());
		paperDetailUnit.setCreateTime(getCurDateTime());
		paperDetailUnit.setQuestion(question);
		paperDetailUnit.setPaperType(PaperType.IMPORT);
		paperDetailUnit.setCreationBy(user.getUserId());
		paperDetailUnit.setCreationDate(new Date());
		return paperDetailUnit;
	}
	
	private void checkPaperName(String rootOrgId,String courseCode,String name) {
		Query query = new Query();
		query.addCriteria(Criteria.where("orgId").is(rootOrgId));
		query.addCriteria(Criteria.where("course.code").is(courseCode));
		query.addCriteria(Criteria.where("name").is(name));
		query.addCriteria(Criteria.where("paperType").is(PaperType.IMPORT.name()));
		List<Paper> ps = mongoTemplate.find(query, Paper.class, "paper");
		if(CollectionUtils.isNotEmpty(ps)) {
			throw new StatusException("该科目下试卷名已存在");
		}
	}
}