package com.ruoyi.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.ZkActivityInfo;
import com.ruoyi.system.domain.bo.CockpitActivityQueryBo;
import com.ruoyi.system.domain.bo.CockpitBo;
import com.ruoyi.system.domain.vo.DeptTreeVo;
import com.ruoyi.system.domain.vo.ZkActivityCountVo;
import com.ruoyi.system.service.*;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class ICockpitServiceImpl implements ICockpitService {

    @Autowired
    private ISysDeptService sysDeptService;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private IZkActivityInfoService activityInfoService;
    @Autowired
    private ISysDictDataService dictDataService;
    @Autowired
    private IZkActivityInfoCountService countService;

    /**
     * @param depts 部门列表
     * @return
     */
    @Override
    public List<DeptTreeVo> buildDeptTree(List<SysDept> depts) {
        List<SysDept> returnList = new ArrayList<>();
        List<Long> tempList = new ArrayList<>();
        for (SysDept dept : depts) {
            tempList.add(dept.getDeptId());
        }
        for (SysDept dept : depts) {
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!tempList.contains(dept.getParentId())) {
                recursionFn(depts, dept);
                returnList.add(dept);
            }
        }
        if (returnList.isEmpty()) {
            returnList = depts;
        }
        return returnList.stream().map(DeptTreeVo::new).collect(Collectors.toList());
    }

    /**
     * 党支部人员信息统计
     *
     * @param bo
     * @return
     */
    @Override
    public Map<String, Object> getDept(CockpitBo bo) {
        Map<String, Object> resultMap = new HashMap<>();
        // 党支部
        List<SysDept> deptList = getDept(bo.getDeptId());
        // 党员
        Integer count = sysUserService.selectCountByDeptId(bo.getDeptId());
        resultMap.put("dzbCount", deptList != null ? deptList.size() : 0);
        resultMap.put("dyCount", count);
        resultMap.put("ybdyCount", 0);
        return resultMap;
    }

    /**
     * 数据格式[{name:'',value:0}]
     * 三会一课——开展频次
     *
     * @param bo
     * @return
     */
    @Override
    public Map<String, Object> getDevelopmentFrequency(CockpitBo bo) {
        Map<String, Object> resultMap;
        List<Map<String, Object>> mapList = new ArrayList<>();
        CockpitActivityQueryBo queryBo = changeBoToQueryBo(bo);
        String[] typeArrResult = new String[]{"支委会", "党小组会", "党员大会", "党课"};
        String[] typeArr = new String[]{"支部委员会", "党小组会", "党员大会", "党课"};
        // 先查询组织id，再查询活动数据
        for (int i = 0; i < typeArr.length; i++) {
            queryBo.setTypeName(typeArr[i]);
            resultMap = new HashMap<>();
            resultMap.put("name", typeArrResult[i]);
            resultMap.put("value", getActivityCount(queryBo));
            mapList.add(resultMap);
        }
        resultMap = new HashMap<>();
        resultMap.put("result", mapList);
        return resultMap;
    }

    /**
     * 三会一课——活动内容 数据格式[{value:0, name:"01XXX", number:"01"}]
     * 数据字典标识：activity_content
     *
     * @param bo
     * @return
     */
    @Override
    public Map<String, Object> getActivityContent(CockpitBo bo) {
        Map<String, Object> resultMap;
        List<Map<String, Object>> mapList = new ArrayList<>();
        // 先查询组织id，再查询活动数据
        CockpitActivityQueryBo queryBo = changeBoToQueryBo(bo);
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType("activity_content");
        List<SysDictData> dictDataList = dictDataService.selectDictDataList(sysDictData);
        for (SysDictData dict : dictDataList) {
            resultMap = new HashMap<>();
            resultMap.put("name", dict.getDictLabel());
            resultMap.put("number", dict.getDictValue());
            // 统计
            queryBo.setContentKey(dict.getDictValue());
            // 设置查询参数
            resultMap.put("value", countService.selectActivityWithContentCount(queryBo));
            mapList.add(resultMap);
        }
        resultMap = new HashMap<>();
        resultMap.put("result", mapList);
        return resultMap;
    }

    /**
     * 三会一课——到会率统计
     * 数据格式{xData:[x,x,x,x],list[0,0,0,0]}
     *
     * @param bo
     * @return
     */
    @Override
    public Map<String, Object> getAttendanceRate(CockpitBo bo) {
        Map<String, Object> resultMap = new HashMap<>();
        String[] xData = new String[]{"支委会", "党小组会", "党员大会", "党课"};
        String[] typeArr = new String[]{"支部委员会", "党小组会", "党员大会", "党课"};
        BigDecimal[] list = new BigDecimal[xData.length];
        CockpitActivityQueryBo queryBo = changeBoToQueryBo(bo);
        for (int i = 0; i < typeArr.length; i++) {
            queryBo.setTypeName(typeArr[i]);
            Long avg = countService.selectActivityAttendanceAvg(queryBo);
            if (avg == null) {
                list[i] = BigDecimal.ZERO.setScale(1, BigDecimal.ROUND_DOWN);
            } else {
                list[i] = new BigDecimal(avg).setScale(1, BigDecimal.ROUND_DOWN);
            }
        }
        resultMap.put("xData", xData);
        resultMap.put("list", list);
        resultMap.put("xData", xData);
        return resultMap;
    }

    /**
     * 三会一课——请假率统计
     * 数据格式{xData:[x,x,x,x],list[0,0,0,0]}
     *
     * @param bo
     * @return
     */
    @Override
    public Map<String, Object> getLeaveRate(CockpitBo bo) {
        Map<String, Object> resultMap = new HashMap<>();
        String[] xData = new String[]{"支委会", "党小组会", "党员大会", "党课"};
        String[] typeArr = new String[]{"支部委员会", "党小组会", "党员大会", "党课"};
        BigDecimal[] list = new BigDecimal[xData.length];
        CockpitActivityQueryBo queryBo = changeBoToQueryBo(bo);
        for (int i = 0; i < typeArr.length; i++) {
            queryBo.setTypeName(typeArr[i]);
            Long avg = countService.selectActivityLeaveAvg(queryBo);
            if (avg == null) {
                list[i] = BigDecimal.ZERO.setScale(1, BigDecimal.ROUND_DOWN);
            } else {
                list[i] = new BigDecimal(avg).setScale(1, BigDecimal.ROUND_DOWN);
            }
        }
        resultMap.put("xData", xData);
        resultMap.put("list", list);
        return resultMap;
    }

    /**
     * 主题党日
     * 数据格式{title:'',count:0,unit=''}
     *
     * @param bo
     * @return
     */
    @Override
    public Map<String, Object> getThemePartyDay(CockpitBo bo) {
        Map<String, Object> resultMap;
        List<Map<String, Object>> mapList = new ArrayList<>();
        CockpitActivityQueryBo queryBo = changeBoToQueryBo(bo);
        String[] titleArr = new String[]{"开展频次", "平均时长", "到会率", "请假率"};
        String[] unitArr = new String[]{"次/月", "分钟", "%", "%"};
        queryBo.setTypeName("主题党日");
        for (int i = 0; i < 4; i++) {
            resultMap = new HashMap<>();
            switch (i) {
                case 0:
                    Integer months = DateUtils.getDifMonth(DateUtils.parseDate(queryBo.getActivityDateBegin()), DateUtils.parseDate(queryBo.getActivityDateEnd()));
                    Long count = getActivityCount(queryBo);
                    BigDecimal monthBig = new BigDecimal(months);
                    BigDecimal countBig = new BigDecimal(count);
                    BigDecimal end = countBig.divide(monthBig).setScale(0, BigDecimal.ROUND_HALF_UP);
                    resultMap.put("count", end.intValue());
                    break;
                case 1:
                    resultMap.put("count", countService.selectActivityDuration(queryBo));
                    break;
                case 2:
                    Long AttendanceAvg = countService.selectActivityAttendanceAvg(queryBo);
                    BigDecimal avgBig = BigDecimal.ZERO;
                    if (AttendanceAvg != null) {
                        avgBig = new BigDecimal(AttendanceAvg);
                    }
                    resultMap.put("count", avgBig.setScale(1, BigDecimal.ROUND_DOWN));
                    break;
                case 3:
                    Long leaveAvg = countService.selectActivityLeaveAvg(queryBo);
                    BigDecimal leaveAvgBig = BigDecimal.ZERO;
                    if (leaveAvg != null) {
                        leaveAvgBig = new BigDecimal(leaveAvg);
                    }
                    resultMap.put("count", leaveAvgBig.setScale(1, BigDecimal.ROUND_DOWN));
                    break;
            }
            resultMap.put("title", titleArr[i]);
            resultMap.put("unit", unitArr[i]);
            mapList.add(resultMap);
        }
        resultMap = new HashMap<>();
        resultMap.put("result", mapList);
        return resultMap;
    }

    /**
     * 组织生活会
     * 数据格式{title:'',count:0,unit=''}
     *
     * @param bo
     * @return
     */
    @Override
    public Map<String, Object> getPartyLife(CockpitBo bo) {
        Map<String, Object> resultMap;
        List<Map<String, Object>> mapList = new ArrayList<>();
        CockpitActivityQueryBo queryBo = changeBoToQueryBo(bo);
        String[] titleArr = new String[]{"累计开展次数", "平均时长", "到会率", "请假率"};
        String[] unitArr = new String[]{"次", "分钟", "%", "%"};
        queryBo.setTypeName("组织生活会");
        for (int i = 0; i < 4; i++) {
            resultMap = new HashMap<>();
            switch (i) {
                case 0:
                    resultMap.put("count", getActivityCount(queryBo));
                    break;
                case 1:
                    resultMap.put("count", countService.selectActivityDuration(queryBo));
                    break;
                case 2:
                    Long AttendanceAvg = countService.selectActivityAttendanceAvg(queryBo);
                    BigDecimal avgBig = BigDecimal.ZERO;
                    if (AttendanceAvg != null) {
                        avgBig = new BigDecimal(AttendanceAvg);
                    }
                    resultMap.put("count", avgBig.setScale(1, BigDecimal.ROUND_DOWN));
                    break;
                case 3:
                    Long leaveAvg = countService.selectActivityLeaveAvg(queryBo);
                    BigDecimal leaveAvgBig = BigDecimal.ZERO;
                    if (leaveAvg != null) {
                        leaveAvgBig = new BigDecimal(leaveAvg);
                    }
                    resultMap.put("count", leaveAvgBig.setScale(1, BigDecimal.ROUND_DOWN));
                    break;
            }
            resultMap.put("title", titleArr[i]);
            resultMap.put("unit", unitArr[i]);
            mapList.add(resultMap);
        }
        resultMap = new HashMap<>();
        resultMap.put("result", mapList);
        return resultMap;
    }

    /**
     * 民主评议
     *
     * @param bo
     * @return
     */
    @Override
    public Map<String, Object> getDemocraticAppraisal(CockpitBo bo) {
        Map<String, Object> resultMap;
        Map<String, Object> itemMap;
        List<Map<String, Object>> mapList = new ArrayList<>();
        CockpitActivityQueryBo queryBo = changeBoToQueryBo(bo);
        String[] nameArr = new String[]{"优秀", "合格", "基本合格", "不合格"};
        String[] colorArr = new String[]{"#F1E402", "#138AF5", "#138AF5", "#2DD7FE"};
        // 条件/总人*100
        List<ZkActivityCountVo> evaluateList = countService.selectActivityEvaluate(queryBo);
        BigDecimal allCount = BigDecimal.ZERO;
        BigDecimal ACount = BigDecimal.ZERO;
        BigDecimal BCount = BigDecimal.ZERO;
        BigDecimal CCount = BigDecimal.ZERO;
        BigDecimal DCount = BigDecimal.ZERO;
        BigDecimal[] bigDecimals = new BigDecimal[]{ACount, BCount, CCount, DCount};
        if (evaluateList != null && evaluateList.size() > 0) {
            for (ZkActivityCountVo countVo : evaluateList) {
                BigDecimal count = new BigDecimal(countVo.getCount());
                if (countVo.getEvaluateType() == 0)
                    ACount = ACount.add(count);
                if (countVo.getEvaluateType() == 1)
                    BCount = BCount.add(count);
                if (countVo.getEvaluateType() == 2)
                    CCount = CCount.add(count);
                if (countVo.getEvaluateType() == 3)
                    DCount = DCount.add(count);
                allCount = allCount.add(count);
            }
            BigDecimal mul = new BigDecimal(100);
            bigDecimals[0] = ACount.divide(allCount, 2, BigDecimal.ROUND_HALF_UP).multiply(mul);
            bigDecimals[1] = BCount.divide(allCount, 2, BigDecimal.ROUND_HALF_UP).multiply(mul);
            bigDecimals[2] = CCount.divide(allCount, 2, BigDecimal.ROUND_HALF_UP).multiply(mul);
            bigDecimals[3] = DCount.divide(allCount, 2, BigDecimal.ROUND_HALF_UP).multiply(mul);
        }
        // 0:优秀 ,1:合格 ,2:基本合格 ,3:不合格
        for (int i = 0; i < nameArr.length; i++) {
            resultMap = new HashMap<>();
            resultMap.put("name", nameArr[i]);
            resultMap.put("value", bigDecimals[i].floatValue());
            itemMap = new HashMap<>();
            itemMap.put("opacity", 0.5);
            itemMap.put("color", colorArr[i]);
            resultMap.put("itemStyle", itemMap);
            mapList.add(resultMap);
        }
        resultMap = new HashMap<>();
        resultMap.put("result", mapList);
        return resultMap;
    }

    /**
     * 组织生活规范指数
     *
     * @param bo
     * @return
     */
    @Override
    public Map<String, Object> getIndex(CockpitBo bo) {
        Map<String, Object> resultMap = new HashMap<>();
        List<Map<String, Object>> mapList = new ArrayList<>();
        CockpitActivityQueryBo queryBo = changeBoToQueryBo(bo);
        String[] typeArr = new String[]{"支部委员会", "党员大会", "党课", "主题党日", "组织生活会", "民主评议"};
        String[] nameArr = new String[]{"规范指数", "组织活动达标率", "组织生活到参会率", "专项活动落实率", "党员个体异常率"};
        // 支委会12次，党员大会4次（季度），党课1次（8月份后），主题党日12次，组织生活会1次（年度），民主评议1次（年度）
        int denominator = 12 + 4 + 12 + 1 + 1;
        String month = DateUtils.dateTimeNow(DateUtils.MM);
        boolean partyFlag = false;
        if (Strings.isNotEmpty(month) && Integer.parseInt(month) > 7) {
            partyFlag = true;
            denominator += 1;
        }
        String deptIds = queryBo.getDeptIdsStr();
        int dzbCount = 0;
        if (Strings.isNotEmpty(deptIds)) {
            dzbCount = deptIds.split(",").length;
        }
        long activityCount = 0;
        // 分母：次数*党支部数
        for (int i = 0; i < typeArr.length; i++) {
            queryBo.setTypeName(typeArr[i]);
            if (i == 2 && !partyFlag) {
                continue;
            }
            activityCount += getActivityCount(queryBo);
        }
        // 达标值
        Map<String, Object> standardValueResultMap = new HashMap<>();
        denominator = denominator * dzbCount;
        BigDecimal denominatorBig = new BigDecimal(denominator);
        BigDecimal activityCountBig = new BigDecimal(activityCount);
        BigDecimal mul = new BigDecimal(100);
        BigDecimal standardValue = activityCountBig.divide(denominatorBig, 2, BigDecimal.ROUND_HALF_UP).multiply(mul);
        standardValueResultMap.put("name", nameArr[1]);
        standardValueResultMap.put("value", standardValue.floatValue());
        mapList.add(standardValueResultMap);
        // 参会率
        Map<String, Object> attendanceRateResultMap = new HashMap<>();
        queryBo.setTypeName("主题党日,党员大会");
        Long attendanceRate = countService.selectActivityAttendanceAvgByTypeList(queryBo);
        attendanceRateResultMap.put("name", nameArr[2]);
        attendanceRateResultMap.put("value", attendanceRate.floatValue());
        mapList.add(attendanceRateResultMap);
        // 专项活动落实率
        Map<String, Object> specialActivityOverResultMap = new HashMap<>();
        List<ZkActivityCountVo> countVoList = countService.selectSpecialActivityStatus(queryBo);
        BigDecimal overRate = BigDecimal.ZERO;
        BigDecimal overCount = BigDecimal.ZERO;
        BigDecimal allCount = BigDecimal.ZERO;
        if (CollectionUtils.isNotEmpty(countVoList)) {
            for (ZkActivityCountVo countVo : countVoList) {
                BigDecimal count = new BigDecimal(countVo.getCount());
                allCount = allCount.add(count);
                if (countVo.getStatus().equals(1)) {
                    overCount = overCount.add(count);
                }
            }
            overRate = overCount.divide(allCount, 2, BigDecimal.ROUND_HALF_UP).multiply(mul);
        }
        specialActivityOverResultMap.put("name", nameArr[3]);
        specialActivityOverResultMap.put("value", overRate.floatValue());
        mapList.add(specialActivityOverResultMap);
        // 党员个体异常率
        Map<String, Object> unUserResultMap = new HashMap<>();
        queryBo.setCount(6);
        Long unUserCount = countService.selectActivityObjUserUnCount(queryBo);
        LambdaQueryWrapper<SysUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(SysUser::getDeptId, getDeptId(bo.getDeptId()));
        lambdaQueryWrapper.eq(SysUser::getIsUser, 1);
        Long userCount = sysUserService.count(lambdaQueryWrapper);
        BigDecimal unUserRate = BigDecimal.ZERO;
        if (unUserCount != null && unUserCount != 0 && userCount != 0) {
            unUserRate = new BigDecimal(unUserCount).divide(new BigDecimal(userCount), 2, BigDecimal.ROUND_HALF_UP).multiply(mul);
        }
        unUserResultMap.put("name", nameArr[4]);
        unUserResultMap.put("value", unUserRate.floatValue());
        mapList.add(unUserResultMap);
        // 指标数据
        float indexCount = standardValue.floatValue() * 5 + overRate.floatValue() + attendanceRate.floatValue()*2;
        BigDecimal indexBig = new BigDecimal(indexCount).divide(new BigDecimal(8));
        indexBig = indexBig.subtract(unUserRate);
        Map<String, Object> indexMap = new HashMap<>();
        indexMap.put("name", nameArr[0]);
        indexMap.put("value", indexBig.floatValue());
        mapList.add(indexMap);
        resultMap.put("result", mapList);
        return resultMap;
    }

    /**
     * 切换查询对象
     *
     * @param bo
     * @return
     */
    public CockpitActivityQueryBo changeBoToQueryBo(CockpitBo bo) {
        CockpitActivityQueryBo queryBo = new CockpitActivityQueryBo();
        queryBo.setDeptIdsStr(getDeptIdStr(bo.getDeptId()));
        if (Strings.isNotEmpty(bo.getActivityDateBegin())) {
            queryBo.setActivityDateBegin(bo.getActivityDateBegin());
            queryBo.setActivityDateEnd(bo.getActivityDateEnd());
        }
        return queryBo;
    }

    /**
     * 获取组织列表（默认查询党支部）
     *
     * @param deptId
     * @return
     */
    private List<SysDept> getDept(Long deptId) {
        QueryWrapper<SysDept> deptLambdaQueryWrapper = new QueryWrapper<>();
        deptLambdaQueryWrapper.lambda().like(SysDept::getDeptName, "党支部");
        deptLambdaQueryWrapper.lambda().and(lq -> {
            lq.eq(SysDept::getDeptId, deptId);
            lq.or().like(SysDept::getAncestors, deptId);
        });
        return sysDeptService.list(deptLambdaQueryWrapper);
    }

    /**
     * 查询组织id集合（默认查询党支部）
     *
     * @param deptId
     * @return
     */
    private List<Long> getDeptId(Long deptId) {
        List<SysDept> deptList = getDept(deptId);
        List<Long> deptIds = new ArrayList<>();
        for (SysDept dept : deptList) {
            deptIds.add(dept.getDeptId());
        }
        return deptIds;
    }

    /**
     * 查询组织id集合（默认查询党支部）
     *
     * @param deptId
     * @return
     */
    private String getDeptIdStr(Long deptId) {
        return StringUtils.join(getDeptId(deptId), ",");
    }

    /**
     * 根据条件查询活动统计数据
     *
     * @param queryBo
     * @return
     */
    private Long getActivityCount(CockpitActivityQueryBo queryBo) {
        QueryWrapper<ZkActivityInfo> lambdaQueryWrapper = new QueryWrapper<>();

        lambdaQueryWrapper.lambda().eq(ZkActivityInfo::getIsDel, 0);
        // 组织id
        lambdaQueryWrapper.lambda().in(queryBo.getDeptIds() != null, ZkActivityInfo::getPDeptId, queryBo.getDeptIds());
        // 活动时间
        if (Strings.isNotEmpty(queryBo.getActivityDateBegin()) && Strings.isNotEmpty(queryBo.getActivityDateEnd())) {
            lambdaQueryWrapper.lambda().apply(
                " date_format(activity_date, '%Y-%m') >= {0} and date_format(activity_date, '%Y-%m') <= {1} ",
                queryBo.getActivityDateBegin(),
                queryBo.getActivityDateEnd()
            );
        }
        if (queryBo.getTypeName() != null) {
            // 活动类型
            String[] typeName = queryBo.getTypeName().split(",");
            lambdaQueryWrapper.lambda().and(lq -> {
                for (int i = 0; i < typeName.length; i++) {
                    lq.or().like(ZkActivityInfo::getTypeName, typeName[i]);
                }
            });
        }
        return activityInfoService.count(lambdaQueryWrapper);
    }

    /**
     * 递归列表
     */
    private void recursionFn(List<SysDept> list, SysDept t) {
        // 得到子节点列表
        List<SysDept> childList = getChildList(list, t);
        t.setChildren(childList);
        for (SysDept tChild : childList) {
            if (hasChild(list, tChild)) {
                recursionFn(list, tChild);
            }
        }
    }

    /**
     * 得到子节点列表
     */
    private List<SysDept> getChildList(List<SysDept> list, SysDept t) {
        List<SysDept> tlist = new ArrayList<>();
        for (SysDept n : list) {
            if (StringUtils.isNotNull(n.getParentId()) && n.getParentId().longValue() == t.getDeptId().longValue()) {
                tlist.add(n);
            }
        }
        return tlist;
    }

    /**
     * 判断是否有子节点
     */
    private boolean hasChild(List<SysDept> list, SysDept t) {
        return getChildList(list, t).size() > 0;
    }

}
