package com.keao.edu.user.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.keao.edu.auth.api.client.SysUserFeignService;
import com.keao.edu.auth.api.entity.SysUser;
import com.keao.edu.common.dal.BaseDAO;
import com.keao.edu.common.enums.MessageTypeEnum;
import com.keao.edu.common.exception.BizException;
import com.keao.edu.common.page.PageInfo;
import com.keao.edu.common.service.SysMessageService;
import com.keao.edu.common.service.impl.BaseServiceImpl;
import com.keao.edu.im.api.client.ImFeignService;
import com.keao.edu.im.api.entity.MemberChangedMessage;
import com.keao.edu.im.api.entity.PublishMessageDto;
import com.keao.edu.thirdparty.message.provider.JiguangPushPlugin;
import com.keao.edu.user.api.entity.ExamRoom;
import com.keao.edu.user.api.entity.ExamRoomStudentRelation;
import com.keao.edu.user.api.entity.Student;
import com.keao.edu.user.api.enums.StudentExamResultApiDto;
import com.keao.edu.user.dao.ExamReviewDao;
import com.keao.edu.user.dao.ExaminationBasicDao;
import com.keao.edu.user.dao.StudentExamResultDao;
import com.keao.edu.user.dto.ExaminationBasicDto;
import com.keao.edu.user.dto.RecordNotify;
import com.keao.edu.user.dto.StudentExamResultStatisticsDto;
import com.keao.edu.user.entity.*;
import com.keao.edu.user.enums.ExamStatusEnum;
import com.keao.edu.user.enums.LevelEnum;
import com.keao.edu.user.page.StudentExamResultQueryInfo;
import com.keao.edu.user.service.ExamRoomService;
import com.keao.edu.user.service.ExamRoomStudentRelationService;
import com.keao.edu.user.service.OrganizationService;
import com.keao.edu.user.service.StudentExamResultService;
import com.keao.edu.util.collection.MapUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class StudentExamResultServiceImpl extends BaseServiceImpl<Long, StudentExamResult> implements StudentExamResultService {

	@Autowired
	private ExaminationBasicDao examinationBasicDao;
	@Autowired
	private StudentExamResultDao studentExamResultDao;
	@Autowired
	private ExamRoomStudentRelationService examRoomStudentRelationService;
	@Autowired
	private OrganizationService organizationService;
	@Autowired
	private SysMessageService sysMessageService;
	@Autowired
	private SysUserFeignService sysUserFeignService;
	@Autowired
	private ImFeignService imFeignService;
	@Autowired
	private ExamRoomService examRoomService;
	@Autowired
	private RedisTemplate<String,String> redisTemplate;
	@Autowired
	private ExamReviewDao examReviewDao;

	private final static Logger logger = LoggerFactory.getLogger(StudentExamResultServiceImpl.class);

	@Override
	public BaseDAO<Long, StudentExamResult> getDAO() {
		return studentExamResultDao;
	}

	@Override
	public PageInfo<StudentExamResult> queryStudentExamResult(StudentExamResultQueryInfo queryInfo) {
		PageInfo<StudentExamResult> pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
		Map<String, Object> params = new HashMap<String, Object>();
		MapUtil.populateMap(params, queryInfo);

		List<Integer> childOrganIds = organizationService.getChildOrganIds(queryInfo.getOrganId(), true);
		params.put("organIds", childOrganIds);

		List<StudentExamResult> dataList = new ArrayList<>();
		int count = studentExamResultDao.countStudentExamResult(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = studentExamResultDao.queryStudentExamResult(params);
			List<Long> examIds = dataList.stream().map(StudentExamResult::getExaminationBasicId).collect(Collectors.toList());
			List<Integer> studentIds = dataList.stream().map(StudentExamResult::getStudentId).collect(Collectors.toList());
			List<Integer> subjectIds = dataList.stream().map(e -> e.getExamRegistration().getSubjectId()).collect(Collectors.toList());
			List<Integer> organIds = dataList.stream().map(e -> e.getExamRegistration().getOrganId()).collect(Collectors.toList());
			Map<Integer, String> studentIdNameMap = this.getMap("sys_user", "id_", "real_name_", studentIds, Integer.class, String.class);
			Map<Integer, String> subjectIdNameMap = this.getMap("subject", "id_", "name_", subjectIds, Integer.class, String.class);
			Map<Integer, String> organIdNameMap = this.getMap("organization", "id_", "name_", organIds, Integer.class, String.class);

			List<ExaminationBasicDto> exams = examinationBasicDao.getExams(examIds);
			Map<Long, ExaminationBasicDto> idExamMap = exams.stream().collect(Collectors.toMap(ExaminationBasic::getId, e -> e));

			for (StudentExamResult s : dataList) {
				Student student=new Student(s.getStudentId(), studentIdNameMap.get(s.getStudentId()));
				s.setExaminationBasic(idExamMap.get(s.getExaminationBasicId()));
				s.getExamRegistration().setSysUser(student);
				s.getExamRegistration().setSubject(new Subject(s.getExamRegistration().getSubjectId(), subjectIdNameMap.get(s.getExamRegistration().getSubjectId())));
				s.getExamRegistration().setOrganization(new Organization(s.getExamRegistration().getOrganId(), organIdNameMap.get(s.getExamRegistration().getOrganId())));
			}
		}
		pageInfo.setRows(dataList);
		return pageInfo;
	}

	@Override
	public void updateStudentExamResult(StudentExamResult studentExamResult) {
		if(Objects.isNull(studentExamResult.getId())){
			throw new BizException("请指定考试结果");
		}
		StudentExamResult oldStudentExamResult = studentExamResultDao.get(studentExamResult.getId());
		if(Objects.isNull(oldStudentExamResult)){
			throw new BizException("考试结果不存在");
		}
		if(Objects.isNull(oldStudentExamResult.getAvgScore())){
			throw new BizException("考试未结束");
		}
		ExaminationBasic examinationBasic = examinationBasicDao.get(oldStudentExamResult.getExaminationBasicId().longValue());
		if(Objects.isNull(examinationBasic)){
			throw new BizException("考级项目不存在");
		}
		if(ExamStatusEnum.RESULT_CONFIRM.equals(examinationBasic.getStatus())||ExamStatusEnum.CLOSE.equals(examinationBasic.getStatus())){
			throw new BizException("考试结果已确认");
		}
		studentExamResultDao.update(studentExamResult);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void examResultConfirmPush(Long examId) {
		if(Objects.isNull(examId)){
			return;
		}
		List<StudentExamResult> studentExamResults = studentExamResultDao.getWithExam(examId);

		Set<Long> examIds = studentExamResults.stream().map(StudentExamResult::getExaminationBasicId).collect(Collectors.toSet());
		Map<Long, String> examIdNameMap = this.getMap("examination_basic", "id_", "name_", new ArrayList(examIds), Long.class, String.class);

		Set<Subject> subjectIds = studentExamResults.stream().map(e -> e.getExamRegistration().getSubject()).collect(Collectors.toSet());
		Map<Integer, String> subjectIdNameMap = this.getMap("subject", "id_", "name_", new ArrayList(subjectIds), Integer.class, String.class);


		String baseUrl = "4?";

		for (StudentExamResult studentExamResult : studentExamResults) {
			String examName = examIdNameMap.get(studentExamResult.getExaminationBasicId());
			String subjectName = subjectIdNameMap.get(studentExamResult.getExamRegistration().getSubjectId());
			String level = LevelEnum.getMsg(studentExamResult.getExamRegistration().getLevel());

			Map<Integer, String> userPhoneMap = new HashMap<>();
			userPhoneMap.put(studentExamResult.getStudentId(), studentExamResult.getStudentId().toString());

			sysMessageService.batchSendMessage(MessageTypeEnum.EXAM_RESULT_CONFIRM_PUSH,
					userPhoneMap, null, 0, baseUrl, JiguangPushPlugin.PLUGIN_NAME,
					examName, subjectName, level, studentExamResult.getResult().getMsg());
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void calculateStudentExamAvgScore(Long examRoomId) {
		List<StudentExamResult> studentExamResults = studentExamResultDao.getWithExamRoom(examRoomId);
		if(CollectionUtils.isEmpty(studentExamResults)){
			return;
		}
		List<ExamReview> examReviews = examReviewDao.getWithExamRoom(examRoomId);
		Map<Long, List<ExamReview>> registReviewMap = examReviews.stream().collect(Collectors.groupingBy(ExamReview::getExamRegistrationId));
		for (StudentExamResult studentExamResult : studentExamResults) {
			List<ExamReview> reviews = registReviewMap.get(studentExamResult.getExamRegistrationId());
			if(CollectionUtils.isEmpty(reviews)){
				studentExamResult.setAvgScore((float) 0);
				continue;
			}
			reviews = reviews.stream().filter(e->Objects.nonNull(e.getEvaluationResult())).collect(Collectors.toList());
			long totalScore = reviews.stream().mapToLong(ExamReview::getEvaluationResult).sum();
			BigDecimal avgScore = new BigDecimal(totalScore).divide(new BigDecimal(reviews.size()), 2, BigDecimal.ROUND_CEILING);
			studentExamResult.setAvgScore(avgScore.floatValue());
		}
		studentExamResultDao.updateRegistAvgScore(studentExamResults);
	}

	@Override
	public StudentExamResultStatisticsDto getStudentExamResultStatisticsInfo(Integer organId, Integer examId) {
		if(Objects.isNull(examId)){
			throw new BizException("请指定考级项目");
		}
		ExaminationBasic examinationBasic = examinationBasicDao.get(examId.longValue());
		if(Objects.isNull(examinationBasic)){
			throw new BizException("考级项目不存在");
		}
		if(examinationBasic.getStatus().getOrder()>ExamStatusEnum.APPLIED.getOrder()){
			return null;
		}
		List<Integer> childOrganIds = organizationService.getChildOrganIds(organId, true);
		StudentExamResultStatisticsDto studentExamResultStatisticsInfo = studentExamResultDao.getStudentExamResultStatisticsInfo(childOrganIds, examId);
		return studentExamResultStatisticsInfo;
	}

	@Override
	public StudentExamResultApiDto getStudentExamResultApiDto(Long id) {
		StudentExamResultApiDto resultApiDto = studentExamResultDao.getStudentExamResultApiDto(id);
		ExamRoomStudentRelation studentExamRoom = examRoomStudentRelationService.getStudentExamRoom(id);
		resultApiDto.setRoomId(studentExamRoom.getExamRoomId().toString());
		return resultApiDto;
	}

	@Override
	public void confirmStudent(Long examRegistrationId) {
		studentExamResultDao.confirmStudent(examRegistrationId);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateFinishedExam(Long examRegistrationId, Integer finishedExam) {
		studentExamResultDao.updateFinishedExam(examRegistrationId,finishedExam);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void recordSync(RecordNotify recordNotify) {
		logger.info("recordSync paramJson{}",recordNotify);
		if (recordNotify.getType() == 4){
			JSONObject jsonObject = JSONObject.parseObject(recordNotify.getOutput());
			if("10000".equals(jsonObject.get("fileState"))){
				String recordId = redisTemplate.opsForValue().get(recordNotify.getRecordId());
				if(StringUtils.isNotEmpty(recordId)){
					redisTemplate.delete(recordNotify.getRecordId());
					Long registrationId = Long.parseLong(recordId);
					StudentExamResult studentExamResult = studentExamResultDao.findByRegistrationId(registrationId);
					String videoUrl = studentExamResult.getVideoUrl();
					if(StringUtils.isNotEmpty(videoUrl)){
						videoUrl += "," + jsonObject.get("fileUrl");
					}else {
						videoUrl = jsonObject.get("fileUrl").toString();
					}
					studentExamResult.setVideoUrl(videoUrl);
					studentExamResultDao.update(studentExamResult);
				}
			}
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void shieldUserId(Long roomId,Integer shieldFlag) {
		ExamRoom examRoom = examRoomService.get(roomId);
		SysUser sysUser = sysUserFeignService.queryUserInfo();
		String userToString = sysUser.getId().toString();
		String shieldUserId = examRoom.getShieldUserId();
		//取消屏蔽
		if(shieldFlag == 0){
			if(StringUtils.isNotEmpty(shieldUserId)){
				if(shieldUserId.contains("," + userToString)){
					shieldUserId = shieldUserId.replace("," + userToString,"");
				}else if(shieldUserId.contains(userToString + ",")){
					shieldUserId = shieldUserId.replace(userToString + ",","");
				}else {
					shieldUserId = "";
				}
			}else {
				shieldUserId = "";
			}
		}else {
			if(StringUtils.isNotEmpty(shieldUserId)){
				if(!shieldUserId.contains(userToString)) {
					shieldUserId += "," + userToString;
				}
			}else {
				shieldUserId = userToString;
			}
		}
		examRoom.setShieldUserId(shieldUserId);
		examRoomService.update(examRoom);
		PublishMessageDto publishMessageDto = new PublishMessageDto();
		publishMessageDto.setUserId(userToString);
		publishMessageDto.setRoomId(roomId.toString());
		MemberChangedMessage msg = new MemberChangedMessage(MemberChangedMessage.Shield_UserId, userToString,3);
		msg.setShieldUserId(shieldUserId);
		publishMessageDto.setMemberChangedMessage(msg);
		imFeignService.publishMessage(publishMessageDto);
	}
}
