package com.xjrsoft.module.student.service.impl;

import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.xjrsoft.module.base.entity.BaseMajorSet;
import com.xjrsoft.module.student.dto.EnrollmentStatisticsCalendarInfoDto;
import com.xjrsoft.module.student.dto.EnrollmentStatisticsGraduationInfoDto;
import com.xjrsoft.module.student.entity.*;
import com.xjrsoft.module.student.mapper.PbCseFeeobjupdateMapper;
import com.xjrsoft.module.student.mapper.PbVXsxxsfytbMapper;
import com.xjrsoft.module.student.service.IPbCseFeeobjupdateService;
import com.xjrsoft.module.student.service.IPbCseSpecplanService;
import com.xjrsoft.module.student.vo.*;
import com.xjrsoft.module.student.dto.EnrollmentStatisticsInfoDto;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @title: 
* @Author szs
* @Date: 2024-03-29
* @Version 1.0
*/
@Service
@AllArgsConstructor
public class PbCseFeeobjupdateServiceImpl extends MPJBaseServiceImpl<PbCseFeeobjupdateMapper, PbCseFeeobjupdate> implements IPbCseFeeobjupdateService {

    @Autowired
    private final IPbCseSpecplanService pbCseSpecplanService;
    private final PbVXsxxsfytbMapper pbVXsxxsfytbMapper;

    @Override
    public EnrollmentStatisticsInfoVo getEnrollmentStatisticsInfo(EnrollmentStatisticsInfoDto dto) {
        EnrollmentStatisticsInfoVo result = new EnrollmentStatisticsInfoVo();
        //获取所有学生的信息
        MPJLambdaWrapper<PbCseFeeobjupdate> pbCseFeeobjupdateMPJLambdaWrapper = new MPJLambdaWrapper<>();
        pbCseFeeobjupdateMPJLambdaWrapper
                .disableSubLogicDel()
                .distinct()
                .selectAs(PbCseFeeobjupdate::getSpecname, PbCseFeeobjupdate::getSpecname)
                .selectAs(PbCseFeeobjupdate::getPersonalid, PbCseFeeobjupdate::getPersonalid)
                .select("IFNULL(resourcename,'无') Resourcename")
//                .selectAs(PbCseFeeobjupdate::getResourcename, PbCseFeeobjupdate::getResourcename)
                .selectAs(PbCseFeeobjupdate::getQuartername, PbCseFeeobjupdate::getQuartername)
                .selectAs(PbCseFeeobjupdate::getSex, PbCseFeeobjupdate::getSex)
                .eq(dto.getYear() != null, PbCseFeeobjupdate::getEnteryear, dto.getYear())
        ;

        List<PbCseFeeobjupdate> pbCseFeeobjupdateList = this.selectJoinList(PbCseFeeobjupdate.class, pbCseFeeobjupdateMPJLambdaWrapper);

        if(pbCseFeeobjupdateList != null && !pbCseFeeobjupdateList.isEmpty()){
            //专业排行
            Map<String, Long> professionalHeadCount = pbCseFeeobjupdateList.stream().filter(x -> x.getSpecname() != null).collect(Collectors.groupingBy(PbCseFeeobjupdate::getSpecname, Collectors.counting()));
            if(!professionalHeadCount.isEmpty()){
                professionalHeadCount = professionalHeadCount.entrySet().stream()
                        .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                                (e1, e2) -> e1, LinkedHashMap::new));
            }
            //查询每个专业的缴费人数
            List<PbVXsxxsfytbSpecnameCountVo> specnameCountVos = pbVXsxxsfytbMapper.getSpecnameCount(dto);
            Map<String, Integer> specnameCountMap = new HashMap<>();
            for (PbVXsxxsfytbSpecnameCountVo specnameCountVo : specnameCountVos) {
                specnameCountMap.put(specnameCountVo.getSpecname(), specnameCountVo.getStudentCount());
            }


            //专业计划人数，余数
            MPJLambdaWrapper<PbCseSpecplan> pbCseSpecplanMPJLambdaWrapper = new MPJLambdaWrapper<>();
            pbCseSpecplanMPJLambdaWrapper
                    .disableSubLogicDel()
                    .distinct()
                    .select("ifnull(t2.name,t.specname) as kkey")
                    .selectAs(PbCseSpecplan::getNum, EnrollmentStatisticsInfoKeyValue::getValue)
                    .leftJoin(BaseMajorSet.class, BaseMajorSet::getName, PbCseSpecplan::getSpecname)
                    .leftJoin(BaseMajorCategor.class, BaseMajorCategor::getId, BaseMajorSet::getMajorCategorId)
                    .eq(dto.getYear() != null, PbCseSpecplan::getXyear, dto.getYear())
            ;

            List<EnrollmentStatisticsInfoKeyValue> pbCseSpecplanList = pbCseSpecplanService.selectJoinList(EnrollmentStatisticsInfoKeyValue.class, pbCseSpecplanMPJLambdaWrapper);

            Map<String, Long>  pbCseSpecplanSumMap = pbCseSpecplanList.stream().collect(Collectors.groupingBy(EnrollmentStatisticsInfoKeyValue::getKkey, Collectors.summingLong(EnrollmentStatisticsInfoKeyValue::getValue)));

            List<ProfessionalHeadCoun> professionalHeadCountRes = new ArrayList<>();
            for (Map.Entry<String, Long> entry : professionalHeadCount.entrySet()) {
                professionalHeadCountRes.add(new ProfessionalHeadCoun(){{
                    setKey(entry.getKey());
                    setValue(entry.getValue());
                    if(pbCseSpecplanSumMap.get(entry.getKey()) != null){
                        setPlannedNumber(pbCseSpecplanSumMap.get(entry.getKey()));
                        setRemainder(pbCseSpecplanSumMap.get(entry.getKey()) - entry.getValue());
                        setPaymentCount(specnameCountMap.get(entry.getKey()));
                    }
                    if(specnameCountMap.get(entry.getKey()) != null){
                        setPaymentCount(specnameCountMap.get(entry.getKey()));
                    }
                }});
            }

            //学生类型
            Map<String, Long> studentSource = pbCseFeeobjupdateList.stream().filter(x -> x.getResourcename() != null).collect(Collectors.groupingBy(PbCseFeeobjupdate::getResourcename, Collectors.counting()));
            List<EnrollmentStatisticsInfoKeyValue> studentSourceRes = new ArrayList<>();
            for (Map.Entry<String, Long> entry : studentSource.entrySet()) {
                studentSourceRes.add(new EnrollmentStatisticsInfoKeyValue(entry.getKey(), entry.getValue()));
            }

            //住宿类型
            Map<String, Long> accommodationType = pbCseFeeobjupdateList.stream().filter(x -> x.getQuartername() != null).collect(Collectors.groupingBy(PbCseFeeobjupdate::getQuartername, Collectors.counting()));
            List<EnrollmentStatisticsInfoKeyValue> accommodationTypeRes = new ArrayList<>();
            for (Map.Entry<String, Long> entry : accommodationType.entrySet()) {
                accommodationTypeRes.add(new EnrollmentStatisticsInfoKeyValue(entry.getKey(), entry.getValue()));
            }

            //性别
            Map<String, Long> gender = pbCseFeeobjupdateList.stream().collect(Collectors.groupingBy(PbCseFeeobjupdate::getSex, Collectors.counting()));
            List<EnrollmentStatisticsInfoKeyValue> genderRes = new ArrayList<>();
            for (Map.Entry<String, Long> entry : gender.entrySet()) {
                genderRes.add(new EnrollmentStatisticsInfoKeyValue(entry.getKey(), entry.getValue()));
            }

            result.setRegistrationPopulation(pbCseFeeobjupdateList.size());
            result.setProfessionalHeadCount(professionalHeadCountRes);
            result.setStudentSource(studentSourceRes);
            result.setAccommodationType(accommodationTypeRes);
            result.setGender(genderRes);

            //获取所有学生的收费明细
            MPJLambdaWrapper<PbCseFeeobjupdate> feeobjupdateXssfdetailMPJLambdaWrapper = new MPJLambdaWrapper<>();
            feeobjupdateXssfdetailMPJLambdaWrapper
                    .select("count(distinct t1.personalid) as payers")
                    .selectSum(PbVXssfdetail::getMny, EnrollmentStatisticsInfoVo::getRecordedAmountOfMoney)
                    .leftJoin(PbVXssfdetail.class, PbVXssfdetail::getPersonalid, PbCseFeeobjupdate::getPersonalid)
                    .eq(dto.getYear() != null, PbCseFeeobjupdate::getEnteryear, dto.getYear())
            ;
            EnrollmentStatisticsInfoVo enrollmentStatisticsInfoVo = this.selectJoinOne(EnrollmentStatisticsInfoVo.class, feeobjupdateXssfdetailMPJLambdaWrapper);

            //退费金额
//            MPJLambdaWrapper<PbCseFeeobjupdate> feeobjupdateXssfdetailMPJLambdaWrapper = new MPJLambdaWrapper<>();
//            feeobjupdateXssfdetailMPJLambdaWrapper
//                    .selectCount(PbVXssfdetail::getPersonalid, EnrollmentStatisticsInfoVo::getPayers)
//                    .selectSum(PbVXssfdetail::getMny, EnrollmentStatisticsInfoVo::getRecordedAmountOfMoney)
//                    .leftJoin(PbVXssfdetail.class, PbVXssfdetail::getPersonalid, PbCseFeeobjupdate::getPersonalid)
//                    .eq(dto.getYear() != null, PbCseFeeobjupdate::getEnteryear, dto.getYear())
//            ;
//            EnrollmentStatisticsInfoVo enrollmentStatisticsInfoVo = this.selectJoinOne(EnrollmentStatisticsInfoVo.class, feeobjupdateXssfdetailMPJLambdaWrapper);

            //缴费人数，入账金额
            if(enrollmentStatisticsInfoVo != null){
                result.setPayers(enrollmentStatisticsInfoVo.getPayers());
                if(enrollmentStatisticsInfoVo.getRecordedAmountOfMoney() != null){
                    result.setRecordedAmountOfMoney(enrollmentStatisticsInfoVo.getRecordedAmountOfMoney().setScale(2, RoundingMode.DOWN));
                }
            }

            //获取所有学生的缴费详情
            MPJLambdaWrapper<PbCseFeeobjupdate> feeobjupdateMPJLambdaWrapper = new MPJLambdaWrapper<>();
            feeobjupdateMPJLambdaWrapper
                    .selectAs(PbCseFeeitem2::getShortname, PbVXssfdetail::getFeeitemname)
                    .selectAs(PbCseFeeobjupdate::getPersonalid, PbVXssfdetail::getPersonalid)
                    .selectAs(PbVXssfdetail::getMny, PbVXssfdetail::getMny)
                    .leftJoin(PbVXssfdetail.class, PbVXssfdetail::getPersonalid, PbCseFeeobjupdate::getPersonalid)
                    .leftJoin(PbCseFeeitem2.class, PbCseFeeitem2::getFeeitemname, PbVXssfdetail::getFeeitemname)
                    .eq(dto.getYear() != null, PbCseFeeobjupdate::getEnteryear, dto.getYear())
                    .isNotNull(PbVXssfdetail::getFeeitemname)
            ;
            List<PbVXssfdetail> pbVXssfdetails = this.selectJoinList(PbVXssfdetail.class, feeobjupdateMPJLambdaWrapper);

            //收费项目情况统计
            Map<String, Long> pbVXssfdetailMap = pbVXssfdetails.stream().collect(Collectors.groupingBy(PbVXssfdetail::getFeeitemname, Collectors.counting()));
            Map<String, BigDecimal>  pbVXssfdetailSumMap = pbVXssfdetails.stream()
                    .collect(Collectors.groupingBy(PbVXssfdetail::getFeeitemname,
                            Collectors.mapping(PbVXssfdetail::getMny, Collectors.reducing(BigDecimal.ZERO, BigDecimal::add))));

            List<ChargingSituationVo> chargingSituationVoRes = new ArrayList<>();
            DecimalFormat df = new DecimalFormat("#.##");
            for (Map.Entry<String, Long> entry : pbVXssfdetailMap.entrySet()) {
                chargingSituationVoRes.add(new ChargingSituationVo(){{
                    setFeeitemname(entry.getKey());
                    setPaid(entry.getValue());
                    if(entry.getKey().equals("普通中专、职业高中、成人中专普通宿舍") && !accommodationType.isEmpty() && accommodationType.get("住宿") != null){
                        setUnpaid(accommodationType.get("住宿") - entry.getValue());
                        setRateOfPayment(df.format((double)entry.getValue()/accommodationType.get("住宿")*100) + "%");
                    } else {
                        setUnpaid(result.getRegistrationPopulation() - entry.getValue());
                        setRateOfPayment(df.format((double)entry.getValue()/result.getRegistrationPopulation()*100) + "%");
                    }
                    if(pbVXssfdetailSumMap.get(entry.getKey()) != null){
                        setRecordedmoney(pbVXssfdetailSumMap.get(entry.getKey()).setScale(2, RoundingMode.DOWN));
                    }
                }});
            }
            result.setChargingSituationVoList(chargingSituationVoRes);
        }

        return result;
    }

    @Override
    public EnrollmentStatisticsCalendarInfoVo getEnrollmentStatisticsCalendarInfo(EnrollmentStatisticsCalendarInfoDto dto) {
        EnrollmentStatisticsCalendarInfoVo result = new EnrollmentStatisticsCalendarInfoVo();
        LocalDate endDate = LocalDate.parse(dto.getEndDay());
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate nextDay = endDate.plusDays(1);
        dto.setEndDay(nextDay.format(formatter));
        String year = String.valueOf(endDate.getYear());
        //根据年月获取招生数量
        MPJLambdaWrapper<PbCseFeeobjupdate> pbCseFeeobjupdateByYearMonth = new MPJLambdaWrapper<>();
        pbCseFeeobjupdateByYearMonth
                .distinct()
                .selectAs(PbCseFeeobjupdate::getPersonalid, PbCseFeeobjupdate::getPersonalid)
                .selectAs(PbCseFeeobjupdate::getCratetime, PbCseFeeobjupdate::getCratetime)
                .eq(PbCseFeeobjupdate::getEnteryear, year)
                .between(PbCseFeeobjupdate::getCratetime, dto.getStartDay(), dto.getEndDay())
        ;

        List<PbCseFeeobjupdate> pbCseFeeobjupdateByYearMonthList = this.selectJoinList(PbCseFeeobjupdate.class, pbCseFeeobjupdateByYearMonth);

        if(pbCseFeeobjupdateByYearMonthList != null && !pbCseFeeobjupdateByYearMonthList.isEmpty()) {
            //每日招生人数
            Map<String, Long> cratetime = pbCseFeeobjupdateByYearMonthList.stream().collect(Collectors.groupingBy(pbCseFeeobjupdate -> pbCseFeeobjupdate.getCratetime().substring(0,10), Collectors.counting()));
            if(!cratetime.isEmpty()){
                cratetime = cratetime.entrySet().stream()
                        .sorted(Map.Entry.comparingByKey())
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                                (e1, e2) -> e1, LinkedHashMap::new));
            }
            List<EnrollmentStatisticsInfoKeyValue> cratetimeRes = new ArrayList<>();
            for (Map.Entry<String, Long> entry : cratetime.entrySet()) {
                cratetimeRes.add(new EnrollmentStatisticsInfoKeyValue(entry.getKey(), entry.getValue()));
            }

            result.setCratetimeList(cratetimeRes);
        }
        return result;
    }

    @Override
    public EnrollmentStatisticsGraduationInfoVo getEnrollmentStatisticsGraduationInfo(EnrollmentStatisticsGraduationInfoDto dto) {
        EnrollmentStatisticsGraduationInfoVo result = new EnrollmentStatisticsGraduationInfoVo();
        LocalDate day = LocalDate.parse(dto.getDay());
        String year = String.valueOf(day.getYear());
        //根据天获取毕业院校
        MPJLambdaWrapper<PbCseFeeobjupdate> pbCseFeeobjupdateByDay = new MPJLambdaWrapper<>();
        pbCseFeeobjupdateByDay
                .distinct()
                .selectAs(PbCseFeeobjupdate::getPersonalid, PbCseFeeobjupdate::getPersonalid)
                .select("ifnull(t.graduations,'未知') as graduations")
                .eq(PbCseFeeobjupdate::getEnteryear, year)
                .like(PbCseFeeobjupdate::getCratetime, day)
        ;
        List<PbCseFeeobjupdate> pbCseFeeobjupdateByDayList = this.selectJoinList(PbCseFeeobjupdate.class, pbCseFeeobjupdateByDay);

        if(pbCseFeeobjupdateByDayList != null && !pbCseFeeobjupdateByDayList.isEmpty()){
            //毕业学校排行
            Map<String, Long> graduations = pbCseFeeobjupdateByDayList.stream().collect(Collectors.groupingBy(PbCseFeeobjupdate::getGraduations, Collectors.counting()));
            if(!graduations.isEmpty()){
                graduations = graduations.entrySet().stream()
                        .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                                (e1, e2) -> e1, LinkedHashMap::new));
            }
            List<EnrollmentStatisticsInfoKeyValue> graduationRes = new ArrayList<>();
            for (Map.Entry<String, Long> entry : graduations.entrySet()) {
                graduationRes.add(new EnrollmentStatisticsInfoKeyValue(entry.getKey(), entry.getValue()));
            }

            result.setGraduationList(graduationRes);
        }

        return result;
    }
}
