package com.hz.pm.api.dashboard.manage;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.hz.pm.api.common.helper.RegionCacheHelper;
import com.hz.pm.api.common.model.constant.RegionConst;
import com.hz.pm.api.common.model.entity.DataDTO;
import com.hz.pm.api.dashboard.model.vo.MeetingStatisticsVO;
import com.hz.pm.api.ding.constants.DingOrganizationContant;
import com.hz.pm.api.expert.constant.ReviewResultEnum;
import com.hz.pm.api.expert.model.entity.ExpertReview;
import com.hz.pm.api.expert.model.enumeration.ReviewTemplateTypeEnum;
import com.hz.pm.api.expert.service.IExpertReviewService;
import com.hz.pm.api.meeting.entity.domain.Meeting;
import com.hz.pm.api.meeting.service.IMeetingService;
import com.hz.pm.api.organization.model.entity.DingOrganization;
import com.hz.pm.api.organization.service.IDingOrganizationService;
import com.hz.pm.api.projectlib.model.entity.Project;
import com.hz.pm.api.projectlib.service.IProjectService;
import com.hz.pm.api.sys.model.dto.RegionDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @Classname MeetingStatisticsManage
 * @Description
 * @Date 2023/12/05 17:44
 * @Author PoffyZhang
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class MeetingStatisticsManage {

    private final IMeetingService meetingService;

    private final IExpertReviewService expertReviewService;

    private final RegionCacheHelper regionCacheHelper;

    private final IDingOrganizationService dingOrganizationService;

    private final IProjectService projectService;

    public MeetingStatisticsVO statistics(Integer year) {
        MeetingStatisticsVO res = new MeetingStatisticsVO();
        List<Meeting> meetings = meetingService.list(Wrappers.lambdaQuery(Meeting.class));
        //查出 年份的 会议数据
        meetings = meetings.stream().filter(m -> {
            if(Objects.nonNull(m.getStartTime()) &&
                    (Objects.isNull(year) || year.equals(m.getStartTime().getYear()))){
                return Boolean.TRUE;
            }
            return Boolean.FALSE;
        }).collect(Collectors.toList());
        List<Long> meetingIds = meetings.stream().map(Meeting::getId)
                .collect(Collectors.toList());

        //会议总数
        res.setMeetingTotal(meetings.size());

        //评审数
        List<ExpertReview> expertReviews = Lists.newArrayList();
        Integer reviewsTotal = 0;
        if(CollUtil.isNotEmpty(meetingIds)){
            expertReviews = expertReviewService.list(Wrappers.lambdaQuery(ExpertReview.class)
                    .eq(ExpertReview::getIsFinal, Boolean.TRUE)
                    .in(ExpertReview::getMeetingId,meetingIds));
            reviewsTotal = expertReviews.size();
        }
        //通过的评审
        List<ExpertReview> passExpertReviews = expertReviews.stream()
                .filter(r -> Objects.nonNull(r.getReviewResult()) &&
                        r.getReviewResult().equals(ReviewResultEnum.PASSED.getCode()))
                .collect(Collectors.toList());
        //不通过的评审
        List<ExpertReview> notpassExpertReviews = expertReviews.stream()
                .filter(r -> Objects.nonNull(r.getReviewResult()) &&
                        r.getReviewResult().equals(ReviewResultEnum.REFUSED.getCode()))
                .collect(Collectors.toList());
        res.setPassReview(passExpertReviews.size());
        res.setNotPassRate(reviewsTotal.compareTo(0) == 0 ? BigDecimal.ZERO :
                BigDecimal.valueOf(notpassExpertReviews.size()).multiply(BigDecimal.valueOf(100)
                .divide(BigDecimal.valueOf(reviewsTotal), RoundingMode.HALF_UP)));

        //各区域
        List<RegionDTO> regions = regionCacheHelper.listChildren(RegionConst.RC_HZ, RegionConst.RL_CITY)
                .stream().filter(r -> r.getRegionLevel().equals(RegionConst.RL_COUNTY))
                .sorted(Comparator.comparing(RegionDTO::getRegionCode)).collect(Collectors.toList());
        List<DataDTO> regionMeetngs = Lists.newArrayList();
        for(RegionDTO region : regions){
            regionMeetngs.add(DataDTO.of(region.getRegionName(),region.getRegionCode(),meetings.stream().filter(m -> {

                return Boolean.FALSE;
            }).collect(Collectors.toList()).size()));
        }
        res.setRegionMeetings(regionMeetngs);

        //预审 验收 会议
        List<DataDTO> meetingTypes = Lists.newArrayList();
        meetingTypes.add(DataDTO.of("预审会议", ReviewTemplateTypeEnum.PRELIMINARY_SCHEME_REVIEW.getCode().toString(),
                meetings.stream().filter(m -> {
                    if(StringUtils.isNotBlank(m.getType()) &&
                            m.getType().equals(ReviewTemplateTypeEnum.PRELIMINARY_SCHEME_REVIEW.getCode()
                                    .toString())){
                        return Boolean.TRUE;
                    }
                    return Boolean.FALSE;
                }).collect(Collectors.toList()).size()));
        Long yanshouCount = meetings.stream().filter(m -> {
            if (StringUtils.isNotBlank(m.getType()) &&
                    m.getType().equals(ReviewTemplateTypeEnum.ACCEPTANCE_SCHEME_REVIEW.getCode()
                            .toString())) {
                return Boolean.TRUE;
            }
            return Boolean.FALSE;
        }).count();
        meetingTypes.add(DataDTO.of("验收会议",ReviewTemplateTypeEnum.ACCEPTANCE_SCHEME_REVIEW.getCode().toString(),
                yanshouCount.intValue()));
        res.setMeetingTypes(meetingTypes);

        //各区县评审 不通过率
        List<DataDTO> regionNotpassReview = Lists.newArrayList();
        for(RegionDTO region : regions){
            DataDTO data = new DataDTO();
            data.setCode(region.getRegionCode());
            data.setName(region.getRegionName());
            //先求出 此区域会议
            List<Long> regionMeetingIds = meetings.stream().filter(m -> Boolean.FALSE).map(Meeting::getId).collect(Collectors.toList());

            List<ExpertReview> regionReviews = expertReviews.stream().filter(r -> {
                if (Objects.nonNull(r.getMeetingId()) &&
                        regionMeetingIds.contains(r.getMeetingId())) {
                    return Boolean.TRUE;
                }
                return Boolean.FALSE;
            }).collect(Collectors.toList());
            long regionNotpass = regionReviews.stream().filter(r -> Objects.nonNull(r.getReviewResult()) &&
                            r.getReviewResult().equals(ReviewResultEnum.REFUSED.getCode()))
                    .count();

            data.setRate(CollUtil.isEmpty(regionReviews) ? BigDecimal.ZERO :
                    BigDecimal.valueOf(regionNotpass).multiply(BigDecimal.valueOf(100))
                            .divide(BigDecimal.valueOf(regionReviews.size()),BigDecimal.ROUND_CEILING,RoundingMode.HALF_UP));

            regionNotpassReview.add(data);
        }
        res.setNotPassRegionMeetings(regionNotpassReview);

        //各部门 不通过项目TOP10
        List<DingOrganization> organizations = dingOrganizationService.list(Wrappers.lambdaQuery(DingOrganization.class)
                .in(DingOrganization::getTypeCode, Lists.newArrayList(DingOrganizationContant.UNIT_TYPE,
                        DingOrganizationContant.GOV_TEMPORARY)));
        List<Project> projects = projectService.list(Wrappers.lambdaQuery(Project.class)
                .eq(Project::getNewest, Boolean.TRUE));

        //TOP10
        List<ExpertReview> finalExpertReviews = expertReviews;
        List<DataDTO> notpassTop10 = organizations.stream()
                .map(o -> {
                    DataDTO data = new DataDTO();
                    data.setCode(o.getOrganizationCode());
                    data.setName(o.getOrganizationName());
                    List<Project> orgProjects = projects.stream().filter(p -> Objects.nonNull(p.getBuildOrgCode()) &&
                                    p.getBuildOrgCode().equals(o.getOrganizationCode()))
                            .collect(Collectors.toList());
                    List<String> projectCodes = orgProjects.stream().map(Project::getProjectCode)
                            .collect(Collectors.toList());
                    if(CollUtil.isEmpty(projectCodes)){
                        return data;
                    }
                    List<ExpertReview> reviews = finalExpertReviews.stream().filter(r -> Objects.nonNull(r.getProjectCode()) &&
                            projectCodes.contains(r.getProjectCode())).collect(Collectors.toList());
                    long orgNotpass = reviews.stream().filter(r -> Objects.nonNull(r.getReviewResult()) &&
                                    r.getReviewResult().equals(ReviewResultEnum.REFUSED.getCode()))
                            .count();
                    data.setRate(CollUtil.isEmpty(reviews) ? BigDecimal.ZERO :
                            BigDecimal.valueOf(orgNotpass).multiply(BigDecimal.valueOf(100))
                                    .divide(BigDecimal.valueOf(reviews.size()),BigDecimal.ROUND_CEILING,RoundingMode.HALF_UP));
                    return data;
                })
                .filter(d -> Objects.nonNull(d.getRate()))
                .sorted(Comparator.comparing(DataDTO::getRate).reversed())
                .limit(10).collect(Collectors.toList());
        res.setNotPassTop10(notpassTop10);
        return res;
    }
}
