package org.shunt.service;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.admin.common.utils.spring.SpringUtils;
import com.admin.common.utils.uuid.IdUtils;
import com.admin.major.domain.Proposal;
import com.admin.major.domain.ProposalFile;
import com.admin.major.domain.SpecialCourseApply;
import com.admin.major.domain.StudentInfo;
import com.admin.major.service.impl.*;
import org.shunt.common.JWTAuthUtil;
import org.shunt.common.XmoseAssert;
import org.shunt.common.XmoseConfigException;
import org.shunt.contorller.request.*;
import org.shunt.contorller.response.ApplyResultVO;
import org.shunt.contorller.response.AuthorDTO;
import org.shunt.contorller.response.MajorApplyViewVO;
import org.shunt.contorller.response.MajorShuntCountVO;
import org.shunt.contorller.response.ScheduleVO;
import org.shunt.contorller.response.ShuntQuotaVO;
import org.shunt.contorller.response.SpecialApplyViewVO;
import org.shunt.contorller.response.StudentScoreVO;
import org.shunt.contorller.response.UserInfoVO;
import org.shunt.mapper.ShuntMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.validation.Valid;

@Service
public class ShuntService {
   @Autowired
   private ShuntMapper mapper;

   @Resource
   private SpecialCourseApplyServiceImpl specialCourseApplyService;


    @Resource
    private ProposalServiceImpl proposalService;


    @Cacheable(value = "shunt:schedule",key = "#authorDTO.collegeId+':'+#authorDTO.yearId")
    public List<ScheduleVO> getSchedule(AuthorDTO authorDTO) {
        return mapper.getSchedule(authorDTO);
    }

    /**
     * 获取日程是否过期
     * 123: 专业分流
     * 122： 特殊申请
     * @param dictCode 字典ID
     * @return 是否过期
     */
    @Cacheable(value = "shunt:isOverSchedule",key = "#authorDTO.collegeId+':'+#authorDTO.yearId+':'+#dictCode")
    public Boolean isOverSchedule(AuthorDTO authorDTO, String dictCode) {
        return mapper.isOverSchedule(authorDTO, dictCode);
    }


    public StudentScoreVO getStudentScore(AuthorDTO authorDTO) {
        return mapper.getStudentScore(authorDTO);
    }

    @Cacheable(value = "shunt:getMajorQuota",key = "#authorDTO.collegeId+':'+#authorDTO.yearId")
    public ShuntQuotaVO getMajorQuota(AuthorDTO authorDTO) {
        ShuntQuotaVO shuntQuotaVO = null;
        List<MajorShuntCountVO> majorShuntCountVOList = mapper.getMajorQuota(authorDTO);
        if (!CollectionUtils.isEmpty(majorShuntCountVOList)) {
            shuntQuotaVO = ShuntQuotaVO.builder().majorShuntCountVOList(majorShuntCountVOList).build();
            shuntQuotaVO.setTotalStudents(majorShuntCountVOList.stream().mapToInt(MajorShuntCountVO::getTotalStudentsNum).sum());
            shuntQuotaVO.setSinUpStudents(majorShuntCountVOList.stream().mapToInt(MajorShuntCountVO::getSinUpStudentsNum).sum());
            shuntQuotaVO.setUnSinUpStudents(shuntQuotaVO.getTotalStudents() - shuntQuotaVO.getSinUpStudents());
        }
        return shuntQuotaVO;
    }

    public SpecialApplyViewVO viewSpecialApply(AuthorDTO authorDTO) {
        SpecialApplyViewVO specialApplyViewVO = mapper.viewSpecialApply(authorDTO);

        if(specialApplyViewVO ==null ){ // null Object
            specialApplyViewVO = new SpecialApplyViewVO();
        }
        if ( !Objects.isNull(specialApplyViewVO.getSpecialApplyId())) {
            specialApplyViewVO.setAttachmentList(mapper.getSpecialApplyAttachment(specialApplyViewVO.getSpecialApplyId()));
        }else{
            specialApplyViewVO.setAttachmentList(Collections.EMPTY_LIST);
        }
        return specialApplyViewVO;
    }

    public ApplyResultVO getSpecialApplyResult(AuthorDTO authorDTO) {
        return mapper.getSpecialApplyResult(authorDTO);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void specialApply(SpecialApplyRequest request, AuthorDTO authorDTO) {
        ShuntService aopProxy = SpringUtils.getAopProxy(this);
        Assert.isTrue(!aopProxy.isOverSchedule(authorDTO,"122"),"不在填写时间范围内");

    	// 判断状态是否是“未提交”
		SpecialApplyViewVO specialApplyViewVO = viewSpecialApply(authorDTO);
		if(!Objects.isNull(specialApplyViewVO.getApplyStatus()) && specialApplyViewVO.getApplyStatus()>0) {
			XmoseAssert.configNotice("提交后，不允许修改");
		}
		// 保存特别申请资料
		mapper.insertSpecialApply(request);

		//删除附件
		if(!Objects.isNull(specialApplyViewVO.getSpecialApplyId())) {
			mapper.deleteSpecialApplyAttachment(specialApplyViewVO.getSpecialApplyId());
		}
		//保存附件
		if(!CollectionUtils.isEmpty(request.getAttachmentList())) {
			specialApplyViewVO = viewSpecialApply(authorDTO);
			final Integer specialApplyId = specialApplyViewVO.getSpecialApplyId();
			request.getAttachmentList().stream().forEach(attachment->
				mapper.insertSpecialApplyAttachment(specialApplyId, attachment, IdUtils.simpleUUID())
			);
		}
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void specialApplySubmit(AuthorDTO authorDTO) {
        mapper.specialApplySubmit(authorDTO);
    }

    public UserInfoVO getUserInfo(AuthorDTO authorDTO) {
        return mapper.getUserInfo(authorDTO);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void setAvatar(AvatarSetRequest request) {
        mapper.setAvatar(request);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void setEmail(EmailSetRequest request) {
        mapper.setEmail(request);
    }

	public MajorApplyViewVO viewMajorApply(AuthorDTO authorDTO) {
		return mapper.viewMajorApply(authorDTO);
	}

	public ApplyResultVO getMajorApplyResult(AuthorDTO authorDTO) {
		return mapper.getMajorApplyResult(authorDTO);
	}

    @Transactional(propagation = Propagation.REQUIRED)
	public void majorApply(MajorApplyRequest request) {
        ShuntService aopProxy = SpringUtils.getAopProxy(this);
        Assert.isTrue(!aopProxy.isOverSchedule(JWTAuthUtil.getAuth(),"123"),"不在填写时间范围内");

        // 判断状态是否是“未提交”
        MajorApplyViewVO mahorViewVO = viewMajorApply(JWTAuthUtil.getAuth());
        if(!Objects.isNull(mahorViewVO.getApplyStatus()) && mahorViewVO.getApplyStatus()>0) {
            XmoseAssert.configNotice("提交后，不允许修改");
        }
		mapper.insertMajorApply(request);
	}
	@Transactional(propagation = Propagation.REQUIRED)
	public void majorApplySubmit(AuthorDTO authorDTO) {
        // 判断状态是否是“未提交”
        MajorApplyViewVO mahorViewVO = viewMajorApply(JWTAuthUtil.getAuth());
        if(!Objects.isNull(mahorViewVO.getApplyStatus()) && mahorViewVO.getApplyStatus()>0) {
            XmoseAssert.configNotice("提交后，不允重复提交");
        }
		mapper.majorApplySubmit(authorDTO);
	}

    public ApplyResultVO getApplyResult(AuthorDTO authorDTO) {
        ApplyResultVO applyResultVO = getSpecialApplyResult(authorDTO);
        if(Objects.isNull(applyResultVO.getApplyStatus()) ||
                applyResultVO.getApplyStatus() == 3){
            applyResultVO = getMajorApplyResult(authorDTO);
        }
        return applyResultVO;
    }

    public boolean saveCourseApply(CourseApplyRequest request, AuthorDTO authorDTO) {
        // 获取提交记录的第一条数据状态，没有即为 0
        List<SpecialCourseApply> applyList = specialCourseApplyService.selectSpecialCourseApplyList(
                new SpecialCourseApply() {{
                    setStudentId(authorDTO.getUserId());
                }});
        String applyStatus = applyList.stream()
                .findFirst()
                .map(SpecialCourseApply::getApplyStatus)
                .orElse("0");
        if( !"0".equals(applyStatus)){// 非0 即已经点击提交了
            XmoseAssert.configNotice("提交后，不允重复提交");
        }

        if(!CollectionUtils.isEmpty(applyList)){// 删除旧数据
            specialCourseApplyService.deleteSpecialCourseApplyBySpecialCourseApplyIds(
                    applyList.stream()
                    .map(SpecialCourseApply::getSpecialCourseApplyId)
                    .toArray(Long[]::new)
            );
        }

        // 批量保存
        List<SpecialCourseApply> courseList = request.getCourseList();
        courseList.forEach(course->{
            course.setStudentId( authorDTO.getUserId() );
            course.setApplyStatus("0");
        });
        return specialCourseApplyService.saveBatch(courseList);
    }

    public void courseApplySubmit(CourseApplyRequest data, AuthorDTO authorDTO) {
        // 判断状态是否是“未提交”
        // 获取提交记录的第一条数据状态，没有即为 0
        List<SpecialCourseApply> applyList = specialCourseApplyService.selectSpecialCourseApplyList(
                new SpecialCourseApply() {{
                    setStudentId(authorDTO.getUserId());
                }});
        String applyStatus = applyList.stream()
                .findFirst()
                .map(SpecialCourseApply::getApplyStatus)
                .orElseThrow(() -> new XmoseConfigException("非法提交申请"));
        if(!"0".equals(applyStatus)) {
            XmoseAssert.configNotice("提交后，不允重复提交");
        }
        mapper.courseApplySubmit(authorDTO);
    }

    public void courseApplyResult(MajorApplyRequest data, AuthorDTO authorDTO) {

    }

    @Transactional
    public void proposalApply(ProposalRequest request) {
        Proposal proposal = new Proposal();
        proposal.setContent(request.getContent());
        proposal.setUserId(request.getUserId());
        proposal.setCreateTime(new Date());

        if (!CollectionUtils.isEmpty(request.getAttachmentList())) {
            List<ProposalFile> collect = request.getAttachmentList().stream()
                    .map(path -> {
                        ProposalFile proposalFile = new ProposalFile();
                        proposalFile.setPath(path);
                        proposalFile.setStatus(1);
                        return proposalFile;
                    }).collect(Collectors.toList());
            proposal.setProposalFileList(collect);
        }

        proposalService.insertProposal(proposal);
        proposalService.insertProposalFile(proposal);
    }
}
