/*
 * Author: Zev
 * 生成ServiceImpl
 */
package com.tofly.gpsboot.service.process.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.tofly.api.UserTaskClient;
import com.tofly.common.oauth.util.SecurityUtils;
import com.tofly.gpsboot.common.Constant;
import com.tofly.gpsboot.common.system.*;
import com.tofly.gpsboot.service.paln.PlanchildtypeService;
import com.tofly.gpsboot.service.paln.PlantypeService;
import com.tofly.gpsboot.util.DateTimeUtil;
import com.tofly.pojo.message.Usertask;
import com.tofly.pojo.plan.*;
import com.tofly.pojo.plan.dto.PointtempDto;
import com.tofly.pojo.plan.vo.PointtempVo;
import com.tofly.gpsboot.mapper.plan.PointtempMapper;
import com.tofly.gpsboot.service.paln.task.PlanService;
import com.tofly.gpsboot.service.paln.task.PlanchildService;
import com.tofly.gpsboot.service.process.PointtempService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;


/**
 * 巡检计划点到位信息表：TF_YWPN_POINTTEMP_W
 *
 * @author admin
 * @date Thu Mar 18 00:00:00 CST 2021
 */
@Service("pointtempService")
@Slf4j
public class PointtempServiceImpl extends ServiceImpl<PointtempMapper, Pointtemp> implements PointtempService {

    @Autowired
    private PlanService planService;

    @Autowired
    private PlanchildService planchildService;
    @Autowired
    private UserTaskClient userTaskClient;
    @Autowired
    private PlantypeService plantypeService;
    @Autowired
    private PlanchildtypeService planchildtypeService;

    @Override
    public List<PointtempVo> viewConversion(List<Pointtemp> infoList) {
        List<PointtempVo> infoVoList = new ArrayList<>();
        infoList.forEach(info -> {
            PointtempVo baseInfo = JSONObject.parseObject(JSONObject.toJSONString(info), PointtempVo.class);
            // 转换是否到位
            baseInfo.setIsoverName(IsPlaceEnum.getCodeForValue(info.getIsover()));
            infoVoList.add(baseInfo);
        });
        return infoVoList;
    }

    @Override
    public Page<PointtempVo> getInfoPage(Page page, PointtempDto parDto) {

        Pointtemp pointtemp = JSONObject.parseObject(JSON.toJSONString(parDto), Pointtemp.class);
        QueryWrapper<Pointtemp> wrapper = new QueryWrapper();

        if (!StringUtils.isEmpty(parDto.getStartTime()) && !StringUtils.isEmpty(parDto.getEndTime())) {
            wrapper.ge("CREATE_TIME", parDto.getStartTime());
            wrapper.le("CREATE_TIME", parDto.getEndTime());
            pointtemp.setCreateTime(null);
        }

        wrapper.setEntity(pointtemp);
        Page infoPageList = this.page(page, wrapper);
        infoPageList.setRecords(this.viewConversion(infoPageList.getRecords()));
        return infoPageList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updatePointTempList(List<Pointtemp> pointtemps) {
        // 相关巡检完成率计算
        // 获取当前用户Id
        Long userid = SecurityUtils.getUser().getUserid();
        // 根据传入参数 点id 获取对应点列表 且为没到位
        List<Pointtemp> pointTempList = new ArrayList<>();

        List<Long> pointIdSet = pointtemps.stream().map(Pointtemp::getId).collect(Collectors.toList());
        int size1 = pointIdSet.size();
        //向上取整 , 获得次数，但是次数不多，只有几次，所以可以使用for循环分段查询
        int count = (int) Math.ceil((double) size1 / 1000d);
        for (int i = 0; i < count; i++) {
            int startIndex = i * 1000;
            int endIndex = 1000 + i * 1000;
            List<Long> subYhbhList;
            //判断是否截取的最后一次数据，如果是最后一次数据，则不能使用endIndex这个参数去截取了，有可能会存在endIndex参数值超过索引最大值的情况
            if (i < count - 1) {
                //分段采取数据 0~999 ； 1000~1999 , 2000~2999 .....//这里subList方法无法截取最后一位，所以需要多写一位索引
                subYhbhList = pointIdSet.subList(startIndex, endIndex);
            } else {
                //分段采取最后的数据
                subYhbhList = pointIdSet.subList(startIndex, pointIdSet.size());
            }
            pointTempList.addAll(this.list(new QueryWrapper<Pointtemp>().lambda()
                    .in(Pointtemp::getId, subYhbhList)
                    .eq(Pointtemp::getIsover, IsPlaceEnum.IS_PLACE_YES.getCode())));
        }
        // 赋值点到为状态为1 更新当前时间
        pointTempList.forEach(f -> {
            f.setIsover(IsPlaceEnum.IS_PLACE_NO.getCode());
            f.setOverDate(new Date());
            f.setUserId(userid);
        });
        // 传入参数 按照计划ID分组
        Map<Long, List<Pointtemp>> collect = pointtemps.stream().collect(Collectors.groupingBy(Pointtemp::getPlanId, Collectors.toList()));
        log.info("collect:{}", JSON.toJSONString(collect));
        // 子计划数据源 按照计划id分组(由于根据用户查询,计划中的子计划只能有一个)
        Map<Long, Planchild> planChildMap = planchildService.list(new QueryWrapper<Planchild>().lambda().eq(Planchild::getRespUser, userid).in(Planchild::getPlanId, collect.keySet())).stream().collect(Collectors.toMap(Planchild::getPlanId, a -> a, (k1, k2) -> k2));
        log.info("planChildMap:{}", JSON.toJSONString(planChildMap));

        // 更新计划类型完成
        collect.forEach((k, v) -> {
            // 子计划
            Planchild planchild = planChildMap.get(k);
            Map<Long, Long> collect1 = v.stream().collect(Collectors.groupingBy(Pointtemp::getInspectTypeId, Collectors.counting()));
            Map<Long, DoubleSummaryStatistics> collect2 = v.stream().filter(i -> null != i.getPipeLength()).collect(Collectors.groupingBy(Pointtemp::getInspectTypeId, Collectors.summarizingDouble(p -> p.getPipeLength().doubleValue())));
            collect1.forEach((m, n) -> {
                List<Plantype> plantypeLists = plantypeService.list(new QueryWrapper<Plantype>().lambda().eq(Plantype::getPlanId, k)
                        .eq(Plantype::getTypeId, m));
                if (null != plantypeLists && plantypeLists.size()>0) {
                    Plantype one = plantypeLists.get(0);
                    BigDecimal overCount = one.getOverCount();
                    BigDecimal overLength = one.getOverLength();
                    BigDecimal totalCount = one.getTotalCount();
                    BigDecimal totalLength = one.getTotalLength();
                    BigDecimal length = (overLength == null ? BigDecimal.ZERO : overLength).add(BigDecimal.valueOf(null == collect2.get(m) ? 0 : collect2.get(m).getSum()));
                    BigDecimal overNum = (overCount == null ? BigDecimal.ZERO : overCount).add(BigDecimal.valueOf(n));
                    BigDecimal multiply = overNum.divide(totalCount, 4, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100));
                    one.setOverCount(overNum);
                    one.setOverLength(length);
                    one.setPercentRate(multiply.floatValue());
                    plantypeService.updateById(one);

                    // 个人完成率
                    List<Planchildtype> list = planchildtypeService.list(new QueryWrapper<Planchildtype>().lambda()
                            .eq(Planchildtype::getTypeId,m)
                            .eq(Planchildtype::getPlanChildId, planchild.getId())
                            .eq(Planchildtype::getUserId, planchild.getRespUser()));
                    Planchildtype planchildtype = new Planchildtype();
                    if (null != list && list.size() > 0) {
                        Planchildtype child = list.get(0);
                        planchildtype.setId(child.getId());
                        planchildtype.setOverCount(child.getOverCount().add(BigDecimal.valueOf(n)));
                        planchildtype.setOverLength(child.getOverLength().add(BigDecimal.valueOf(null == collect2.get(m) ? 0 : collect2.get(m).getSum())));
                        planchildtype.setPercentRate(planchildtype.getOverCount().divide(totalCount, 4, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100)).floatValue());
                    } else {
                        planchildtype.setOverCount(overNum);
                        planchildtype.setOverLength(length);
                        planchildtype.setPercentRate(multiply.floatValue());
                    }
                    planchildtype.setPlanChildId(planchild.getId());
                    planchildtype.setUserId(planchild.getRespUser());
                    planchildtype.setTotalCount(totalCount);
                    planchildtype.setTotalLength(totalLength);
                    planchildtype.setCompletionRate(one.getCompletionRate());
                    planchildtype.setTypeId(one.getTypeId());
                    planchildtypeService.saveOrUpdate(planchildtype);
                }
            });

        });
        // 存入完成计划id
        Set<Long> overPlanList = new HashSet<>();

        // 判断当前计划对应的类型计划是否达到对应的计划完成率

        collect.keySet().forEach(k -> {
            List<Plantype> planTypeList = plantypeService.list(new QueryWrapper<Plantype>().lambda().eq(Plantype::getPlanId, k));
            if(null!=planTypeList && planTypeList.size()>0){
                int size = planTypeList.size();
                AtomicInteger overNum = new AtomicInteger();
                planTypeList.forEach(planType -> {
                    float completionRate = planType.getCompletionRate()==null?0:planType.getCompletionRate();
                    float percent = planType.getPercentRate()==null?0:planType.getPercentRate();
                    if (completionRate<=percent) {
                        overNum.set(overNum.get() + 1);
                    }
                });
                if (size == overNum.get()) {
                    overPlanList.add(k);
                    // 待办事项处理
                    Usertask usertask = new Usertask();
                    usertask.setTableName(MessageTopicEnum.TASK_PLAN_SEND.getTableName());
                    usertask.setTableId(k);
                    List<Usertask> result = userTaskClient.getUserTaskInfo(usertask).getResult();
                    if (null != result && result.size() > 0) {
                        result.forEach(task -> {
                            task.setHandleTime(DateTimeUtil.convertLDTToDate(LocalDateTime.now()));
                            task.setIshandle(UserTaskStateEnumEnum.IS_HANDLER_COMPLETED.getCode());
                            userTaskClient.updateById(task);
                        });

                    }
                }
            }


        });

        if(overPlanList.size()>0){
            // 更新计划及子计划
            planService.update(new UpdateWrapper<Plan>().lambda().in(Plan::getId,overPlanList)
                    .set(Plan::getPlanState,PlanStateEnum.PLAN_STATE_PLAN_COMPLETE.getCode()));
            // 主计划完成 批量修改主计划下对应子计划状态
            planchildService.update(new UpdateWrapper<Planchild>().lambda().in(Planchild::getPlanId,overPlanList)
                    .set(Planchild::getPlanState,IsPlanChildStateEnum.PLAN_STATE_PLAN_COMPLETE.getCode()));
        }

        return this.updateBatchById(pointTempList);
    }

    /**
     * 获取当前计划下 实际已完成到位点个数(过滤多用户)
     *
     * @param planId
     * @param overIds
     * @return
     */
    private Integer getPlanCompleteNumerical(Long planId, String overIds) {
        List<String> collect = planchildService.list(new QueryWrapper<Planchild>().lambda().eq(Planchild::getPlanId, planId)).stream().map(Planchild::getOverIds).collect(Collectors.toList());
        Set<Long> tempIdList = new HashSet<>();
        collect.forEach(ids -> {
            if (!StringUtils.isEmpty(ids)) {
                tempIdList.addAll(Arrays.stream(ids.split(Constant.CSV)).map(s -> Long.parseLong(s.trim()))
                        .collect(Collectors.toList()));
            }
        });
        if (!StringUtils.isEmpty(overIds)) {
            tempIdList.addAll(Arrays.stream(overIds.split(Constant.CSV)).map(s -> Long.parseLong(s.trim()))
                    .collect(Collectors.toList()));
        }
        return tempIdList.size();


    }


}
