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

import com.keao.edu.common.dal.BaseDAO;
import com.keao.edu.common.exception.BizException;
import com.keao.edu.common.page.PageInfo;
import com.keao.edu.common.service.impl.BaseServiceImpl;
import com.keao.edu.common.tenant.TenantContextHolder;
import com.keao.edu.user.api.entity.ExamRoom;
import com.keao.edu.user.api.entity.ExamRoomStudentRelation;
import com.keao.edu.user.dao.*;
import com.keao.edu.user.dto.*;
import com.keao.edu.user.entity.ExamTeacherSalary;
import com.keao.edu.user.entity.Teacher;
import com.keao.edu.user.enums.TeacherSettlementTypeEnum;
import com.keao.edu.user.page.ExamTeacherSalaryQueryInfo;
import com.keao.edu.user.service.ExamTeacherSalaryService;
import com.keao.edu.util.collection.MapUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
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 ExamTeacherSalaryServiceImpl extends BaseServiceImpl<Long, ExamTeacherSalary> implements ExamTeacherSalaryService {

	@Autowired
	private ExamRoomDao examRoomDao;
	@Autowired
	private ExamRoomStudentRelationDao examRoomStudentRelationDao;
	@Autowired
	private ExamTeacherSalaryDao examTeacherSalaryDao;
	@Autowired
	private TeacherDao teacherDao;
	@Autowired
	private ExaminationBasicDao examinationBasicDao;

	@Override
	public BaseDAO<Long, ExamTeacherSalary> getDAO() {
		return examTeacherSalaryDao;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void teacherSalarySettlementWithExam(Long examId) {
		List<ExamRoom> examRooms = examRoomDao.getWithExam(null, examId);
		if(CollectionUtils.isEmpty(examRooms)){
			examRooms=Collections.EMPTY_LIST;
		}

		Map<Integer, List<ExamRoom>> teacherExamRoomMap=new HashMap<>();
		for (ExamRoom examRoom : examRooms) {
			if(!teacherExamRoomMap.containsKey(examRoom.getMainTeacherUserId())){
				teacherExamRoomMap.put(examRoom.getMainTeacherUserId(), new ArrayList<>());
			}
			teacherExamRoomMap.get(examRoom.getMainTeacherUserId()).add(examRoom);
			if(StringUtils.isBlank(examRoom.getAssistantTeacherUserIdList())){
				continue;
			}
			for (String assistantTeacherId : examRoom.getAssistantTeacherUserIdList().split(",")) {
				if(!teacherExamRoomMap.containsKey(Integer.valueOf(assistantTeacherId))){
					teacherExamRoomMap.put(Integer.valueOf(assistantTeacherId), new ArrayList<>());
				}
				teacherExamRoomMap.get(Integer.valueOf(assistantTeacherId)).add(examRoom);
			}
		}

		List<ExamRoomStudentRelation> examRoomStudentRelations = examRoomStudentRelationDao.getExamRoomStudentRelations(examId, null, null);

		List<ExamTeacherSalary> examTeacherSalaries = examTeacherSalaryDao.queryWithExam(examId);
		for (ExamTeacherSalary examTeacherSalary : examTeacherSalaries) {
			List<ExamRoom> teacherExamRooms = teacherExamRoomMap.get(examTeacherSalary.getTeacherId());
			if(CollectionUtils.isEmpty(teacherExamRooms)){
				examTeacherSalary.setTotalInvigilationNum(0);
				examTeacherSalary.setTotalInvigilationStudentNum(0);
				examTeacherSalary.setTotalSettlementCost(BigDecimal.ZERO);
				continue;
			}
			Set<Long> examRoomIds = teacherExamRooms.stream().map(ExamRoom::getId).collect(Collectors.toSet());
			long studentNum = examRoomStudentRelations.stream().filter(e -> examRoomIds.contains(e.getExamRoomId())).count();
			examTeacherSalary.setTotalInvigilationNum(examRoomIds.size());
			examTeacherSalary.setTotalInvigilationStudentNum((int) studentNum);
			if(TeacherSettlementTypeEnum.SINGLE.equals(examTeacherSalary.getSettlementType())){
				examTeacherSalary.setTotalSettlementCost(examTeacherSalary.getShareProfitAmount().multiply(new BigDecimal(examRoomIds.size())));
			}else if(TeacherSettlementTypeEnum.PEOPLE_NUM.equals(examTeacherSalary.getSettlementType())){
				examTeacherSalary.setTotalSettlementCost(examTeacherSalary.getShareProfitAmount().multiply(new BigDecimal(studentNum)));
			}

		}
		if(!CollectionUtils.isEmpty(examTeacherSalaries)){
			examTeacherSalaryDao.batchUpdate(examTeacherSalaries);
			Set<Integer> teacherIds = examTeacherSalaries.stream().map(ExamTeacherSalary::getTeacherId).collect(Collectors.toSet());
			List<ExamTeacherSalary> teacherAllExamSalarys = examTeacherSalaryDao.getWithTeachers(new ArrayList<>(teacherIds));
			Map<Integer, List<ExamTeacherSalary>> teacherExamSalarysMap = teacherAllExamSalarys.stream().collect(Collectors.groupingBy(ExamTeacherSalary::getTeacherId));
			List<Teacher> updateTeachers=new ArrayList<>();
			for (Integer teacherId : teacherIds) {
				List<ExamTeacherSalary> examSalarys = teacherExamSalarysMap.get(teacherId);
				Integer totalInvigilationNum=0;
				Integer totalInvigilationStudentNum=0;
				BigDecimal totalSettlementCost=BigDecimal.ZERO;
				if(!CollectionUtils.isEmpty(examSalarys)){
					for (ExamTeacherSalary examSalary : examSalarys) {
						totalInvigilationNum += examSalary.getTotalInvigilationNum();
						totalInvigilationStudentNum += examSalary.getTotalInvigilationStudentNum();
						totalSettlementCost=totalSettlementCost.add(examSalary.getTotalSettlementCost());
					}
				}
				Teacher teacher=new Teacher();
				teacher.setUserId(teacherId);
				teacher.setTotalInvigilationNum(totalInvigilationNum);
				teacher.setTotalInvigilationStudentNum(totalInvigilationStudentNum);
				teacher.setTotalSettlementCost(totalSettlementCost);
				updateTeachers.add(teacher);
			}
			if(!CollectionUtils.isEmpty(updateTeachers)){
				teacherDao.batchUpdate(updateTeachers);
			}
		}
	}

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

		List<ExamTeacherSalaryDto> dataList = new ArrayList<>();
		int count = examTeacherSalaryDao.countExamTeacherSalary(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = examTeacherSalaryDao.queryExamTeacherSalary(params);
			List<Long> examIds = dataList.stream().map(ExamTeacherSalaryDto::getExaminationBasicId).collect(Collectors.toList());
			List<ExaminationBasicDto> exams = examinationBasicDao.getExams(examIds);
			Map<Long, ExaminationBasicDto> idExamMap = exams.stream().collect(Collectors.toMap(ExaminationBasicDto::getId, e -> e));
			for (ExamTeacherSalaryDto examTeacherSalaryDto : dataList) {
				examTeacherSalaryDto.setExaminationBasic(idExamMap.get(examTeacherSalaryDto.getExaminationBasicId()));
			}
		}
		pageInfo.setRows(dataList);
		return pageInfo;
	}

	@Override
	public void deleteExamTeacherSalary(Long examTeacherSalaryId) {
		ExamTeacherSalary examTeacherSalary = examTeacherSalaryDao.get(examTeacherSalaryId);
		if(Objects.isNull(examTeacherSalary)){
			throw new BizException("教室分润设置不能存在");
		}
		if(examTeacherSalary.getTotalInvigilationNum()>0){
			throw new BizException("该教室已被分配到考场");
		}
		examTeacherSalaryDao.delete(examTeacherSalaryId);
	}

	@Override
	public void addExamTeacherSalary(Long examId, String teacherIdsStr) {
		if(Objects.isNull(examId)){
			throw new BizException("请指定考级项目");
		}
		if(StringUtils.isBlank(teacherIdsStr)){
			throw new BizException("请指定教师");
		}
		List<Integer> teacherIds = Arrays.stream(teacherIdsStr.split(",")).map(e -> Integer.valueOf(e)).collect(Collectors.toList());
		List<ExamTeacherSalary> withExamAndTeacher = examTeacherSalaryDao.getWithExamAndTeacher(examId, teacherIds);
		if(!CollectionUtils.isEmpty(withExamAndTeacher)){
			List<String> teacherNames = withExamAndTeacher.stream().map(e -> e.getTeacher().getRealName()).collect(Collectors.toList());
			throw new BizException("{}教师已存在", teacherNames);
		}
		List<Teacher> teachers = teacherDao.getWithTeachers(teacherIds);
		Map<Integer, Teacher> idTeacherMap = teachers.stream().collect(Collectors.toMap(Teacher::getUserId, t -> t));

		List<ExamTeacherSalary> examTeacherSalaries=new ArrayList<>();
		for (Integer teacherId : teacherIds) {
			Teacher teacher = idTeacherMap.get(teacherId);
			if(Objects.isNull(teacher)){
				throw new BizException("教师信息异常");
			}
			ExamTeacherSalary ets=new ExamTeacherSalary();
			ets.setExaminationBasicId(examId);
			ets.setTeacherId(teacherId);
			ets.setSettlementType(teacher.getSalarySettlementType());
			ets.setShareProfitAmount(teacher.getSalary());
			ets.setTotalSettlementCost(BigDecimal.ZERO);
			ets.setTotalInvigilationStudentNum(0);
			ets.setTotalInvigilationNum(0);
			ets.setTenantId(TenantContextHolder.getTenantId());
			examTeacherSalaries.add(ets);
		}
		examTeacherSalaryDao.batchInsert(examTeacherSalaries);
	}

	@Override
	public void updateExamTeacherSalary(ExamTeacherSalary examTeacherSalary) {
		if(Objects.isNull(examTeacherSalary.getId())){
			throw new BizException("参数错误");
		}
		ExamTeacherSalary exist = examTeacherSalaryDao.get(examTeacherSalary.getId());
		if(Objects.isNull(exist)){
			throw new BizException("参数错误");
		}
		examTeacherSalaryDao.update(examTeacherSalary);
		teacherSalarySettlementWithExam(exist.getExaminationBasicId());
	}

	@Override
	public List<BaseUserInfoDto> getExamTeachers(Integer examId) {
		if(Objects.isNull(examId)){
			throw new BizException("请指定考级项目");
		}
		return examTeacherSalaryDao.getTeachersWithExam(examId);
	}

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

		List<TeacherDto> dataList = new ArrayList<>();
		int count = examTeacherSalaryDao.countUnRelatedWithExamTeachers(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = examTeacherSalaryDao.queryUnRelatedWithExamTeachers(params);
			List<Integer> subjectIds=new ArrayList<>();
			for (TeacherDto teacher : dataList) {
				if(StringUtils.isBlank(teacher.getSubjectIdList())){
					continue;
				}
				for (String subjectId : teacher.getSubjectIdList().split(",")) {
					if(!subjectIds.contains(Integer.valueOf(subjectId))){
						subjectIds.add(Integer.valueOf(subjectId));
					}
				}
			}
			if(!CollectionUtils.isEmpty(subjectIds)){
				Map<Integer, String> subjectIdNameMap = this.getMap("subject", "id_", "name_", subjectIds, Integer.class, String.class);
				for (TeacherDto teacher : dataList) {
					if(StringUtils.isBlank(teacher.getSubjectIdList())){
						continue;
					}
					List<String> subjectNames=new ArrayList<>();
					for (String subjectId : teacher.getSubjectIdList().split(",")) {
						String subjectName = subjectIdNameMap.get(Integer.valueOf(subjectId));
						if(StringUtils.isNotBlank(subjectName)){
							subjectNames.add(subjectName);
						}
					}
					teacher.setSubjectNames(StringUtils.join(subjectNames, ","));
				}
			}
		}

		pageInfo.setRows(dataList);
		return pageInfo;
	}

	@Override
	public ExamTeacherSalaryStaticsInfo getExamTeacherSalaryStaticsInfo(Integer examId) {
		if(Objects.isNull(examId)){
			throw new BizException("请指定考级项目");
		}
		return examTeacherSalaryDao.getExamTeacherSalaryStaticsInfo(examId);
	}
}
