package com.willalp.yiqing.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.willalp.common.core.redis.RedisCache;
import com.willalp.common.exception.base.BaseException;
import com.willalp.common.utils.DateUtils;
import com.willalp.common.utils.StringUtils;
import com.willalp.common.utils.bean.BeanUtils;
import com.willalp.yiqing.domain.HsPositiveContiguityUser;
import com.willalp.yiqing.domain.HsYiqingRnsResult;
import com.willalp.yiqing.domain.vo.HomeDataVo;
import com.willalp.yiqing.domain.vo.OrdersVo;
import com.willalp.yiqing.domain.vo.PcuVo;
import com.willalp.yiqing.domain.vo.RegisterVo;
import com.willalp.yiqing.mapper.HsPositiveContiguityUserMapper;
import com.willalp.yiqing.service.IHsPositiveContiguityUserService;
import com.willalp.yiqing.service.IHsYiqingRnsResultService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 阳性及密接人员Service业务层处理
 *
 * @author willalp
 * @date 2022-05-15
 */
@Service
public class HsPositiveContiguityUserServiceImpl extends ServiceImpl<HsPositiveContiguityUserMapper, HsPositiveContiguityUser> implements IHsPositiveContiguityUserService {
    @Resource
    private HsPositiveContiguityUserMapper pcuMapper;

    @Resource
    private IHsYiqingRnsResultService rnsResultService;

    @Resource
    private RedisCache redisCache;

    @Resource
    private HomeDataVo homeDataVo;

    @Resource(name = "asyncServiceExecutor")
    private Executor asyncServiceExecutor;

    /**
     * 查询阳性及密接人员列表
     *
     * @param pcuVo@return 阳性及密接人员
     */
    @Override
    public List<HsPositiveContiguityUser> selectHsPositiveContiguityUserList(PcuVo pcuVo) {
        if (pcuVo.getListType() == 0) {
            return pcuMapper.selectHsPositiveContiguityUserList(pcuVo);
        }
        QueryWrapper<HsYiqingRnsResult> qw2 = new QueryWrapper<>();
        String rnaResult = pcuVo.getRnaResult();
        if (StringUtils.isNotBlank(rnaResult)) {
            qw2.eq("rna_result", rnaResult);
        }
        List<HsPositiveContiguityUser> pcuDb = pcuMapper.selectPcuJJGlList(pcuVo);
        List<HsYiqingRnsResult> rnsResultsDb = rnsResultService.getBaseMapper().selectList(qw2);
        pcuDb.forEach(p -> {
            if (ObjectUtil.isEmpty(p.getNormalTime())) {
                p.setNormalTime(p.getExceptionRegisterTime());
            }
            List<HsYiqingRnsResult> saveRnsResults = new ArrayList<>();
            AtomicInteger num = new AtomicInteger();
            rnsResultsDb.forEach(r -> {
                if (StringUtils.equals(p.getDataId(), r.getUserDataId())) {
                    num.getAndIncrement();
                    saveRnsResults.add(r);
                }
            });
            p.setRnsResults(saveRnsResults.stream()
                    .sorted(Comparator.comparing(HsYiqingRnsResult::getSamplingTime))
                    .collect(Collectors.toList()));
        });
        return pcuDb;
    }

    @Override
    public String importData(List<HsPositiveContiguityUser> list) {
        if (0 != list.size()) {
            List<HsPositiveContiguityUser> usersDb = baseMapper.selectList(null);
            List<HsPositiveContiguityUser> saveList = new ArrayList<>();
            List<HsPositiveContiguityUser> updateList = new ArrayList<>();
            int errorCount = 0;
            if (0 != usersDb.size()) {
                try {
                    for (HsPositiveContiguityUser vo : list) {
                        int num = 0;
                        for (HsPositiveContiguityUser user : usersDb) {
                            if (StringUtils.equals(vo.getUserName(), user.getUserName()) &&
                                    StringUtils.equals(vo.getAttestNo(), user.getAttestNo())) {
                                String id = user.getDataId();
                                BeanUtils.copyBeanProp(user, vo);
                                user.setDataId(id);
                                user.setUserNo(vo.getUserNo());
                                user.setNormalStatus(vo.getNormalStatus());
                                user.setTransferType(vo.getTransferType());
                                user.setTransferTime(vo.getTransferTime());
                                user.setExceptionRegisterType(vo.getExceptionRegisterType());
                                user.setExceptionRegisterTime(vo.getExceptionRegisterTime());
                                user.setAddress(vo.getAddress());
                                user.setAreaName(vo.getAreaName());
                                user.setOtherAttest(vo.getOtherAttest());
                                updateList.add(user);
                                num++;
                                break;
                            }
                        }
                        if (0 == num) {
                            saveList.add(vo);
                        }
                    }
                } catch (Exception e) {
                    errorCount++;
                }
            } else {
                saveList.addAll(list);
            }
            if (0 != updateList.size()) {
                if (!this.updateBatchById(updateList)) {
                    throw new BaseException("批量导入失败");
                }
            }
            if (0 != saveList.size()) {
                if (!this.saveBatch(saveList)) {
                    throw new BaseException("批量导入失败");
                }
            }
            redisCache.setCacheObject("isPcuHomeUpdate", 0, 1, TimeUnit.HOURS);
            return "导入成功，共导入 " + (saveList.size() + updateList.size()) + " 条新记录，无效数据 " + errorCount + " 条";
        }
        return "无有效数据";
    }

    @Override
    public List<RegisterVo> ordersImport(OrdersVo ordersVo) {
        Date orderImportTime = ordersVo.getOrderImportTime();
        if (ObjectUtil.isNull(orderImportTime)) {
            throw new BaseException("派单发起时间不能为空");
        }
        Integer registerGapDay = ordersVo.getRegisterGapDay();
        PcuVo pcu = new PcuVo();
        BeanUtils.copyBeanProp(pcu, ordersVo);
        pcu.setListType(1);
        pcu.setNormalStatus(ordersVo.getNormalStatus1());
        List<HsPositiveContiguityUser> rnaResultAndUsers = this.selectHsPositiveContiguityUserList(pcu);
        List<HsPositiveContiguityUser> updatePcuList = new ArrayList<>();
        List<RegisterVo> list = new ArrayList<>();
        AtomicReference<Integer> no = new AtomicReference<>(1);
        rnaResultAndUsers.forEach(ru -> {
            int num = 0;
            Date normalTime = ru.getNormalTime();
            if (ObjectUtil.isNotNull(normalTime)) {
                List<HsYiqingRnsResult> rnsResults = ru.getRnsResults();
                //登记后 n 天内
                DateTime registerBackDay = DateUtil.offsetDay(normalTime, registerGapDay);
                String s = registerBackDay.toString("yyyy-MM-dd");
                //是否筛选了核酸结果
                int isNotTime = 0;
                if (StringUtils.isBlank(ordersVo.getRnaResult())) {
                    if (0 == registerGapDay) {
                        num++;
                    } else if (0 != rnsResults.size()) {
                        for (HsYiqingRnsResult rns : rnsResults) {
                            //采样时间是登记时间后 N 天 并且 应测未测 为 false 取反 true
                            //采样时间不是登记时间后 N 天 返回false 取反 true
                            if (DateUtils.parseDateToStr("yyyy-MM-dd", rns.getSamplingTime()).contains(s)) {
                                isNotTime = 0;
                                if (rns.getRnaResult().equals("应测未测")) {
                                    num++;
                                } else {
                                    num = 0;
                                }
                            } else {
                                isNotTime++;
                            }
                        }
                        if (0 != isNotTime) {
                            num++;
                        }
                    } else {
                        num++;
                    }
                } else {
                    if (0 == registerGapDay) {
                        for (HsYiqingRnsResult rns : rnsResults) {
                            if (rns.getRnaResult().equals(ordersVo.getRnaResult())) {
                                num++;
                            } else {
                                num = 0;
                            }
                        }
                    } else if (0 != rnsResults.size()) {
                        for (HsYiqingRnsResult rns : rnsResults) {
                            if (DateUtils.parseDateToStr("yyyy-MM-dd", rns.getSamplingTime())
                                    .contains(s)) {
                                if (rns.getRnaResult().equals(ordersVo.getRnaResult())) {
                                    num++;
                                } else {
                                    num = 0;
                                }
                            } else {
                                isNotTime++;
                            }
                        }
                        if (0 != isNotTime) {
                            num++;
                        }
                    } else {
                        num++;
                    }
                }
                if (num > 0) {
                    String date = DateUtil.formatDate(orderImportTime);
                    ru.setSevenSendOrders(date);
                    updatePcuList.add(ru);
                    RegisterVo registerVo = new RegisterVo();
                    BeanUtils.copyBeanProp(registerVo, ru);
                    registerVo.setSendOrdersEnd(date);
                    list.add(registerVo);
                    no.getAndSet(no.get() + 1);
                }
            }
        });
        asyncServiceExecutor.execute(() -> asyncUpdate(updatePcuList));
        List<RegisterVo> collect = list.stream()
                .sorted(Comparator.comparing(RegisterVo::getUserNo)).collect(Collectors.toList());
        return collect;
    }

    public void asyncUpdate(List<HsPositiveContiguityUser> updatePcuList) {
        if (0 != updatePcuList.size()) {
            if (!this.updateBatchById(updatePcuList)) {
                throw new BaseException("异步更新 - 派单时间失败，请重试");
            }
        }
    }

    private boolean isCount(String sd, String jw, HsPositiveContiguityUser p, String[] strArray,
                            Map<String, Integer> map) {
        if (StringUtils.isNotBlank(sd)) {
            redisCache.setCacheObject("isPcuHomeUpdate", 1, 1, TimeUnit.HOURS);
            String areaName = p.getAreaName();
            if (StringUtils.isNotBlank(areaName)) {
                if (!sd.contains(areaName)) {
                    return false;
                }
            } else {
                return false;
            }
        }
        if (StringUtils.isNotBlank(jw)) {
            redisCache.setCacheObject("isPcuHomeUpdate", 1, 1, TimeUnit.HOURS);
            String houseNo = p.getHouseNo();
            if (StringUtils.isNotBlank(houseNo)) {
                if (!jw.contains(houseNo)) {
                    return false;
                }
            } else {
                return false;
            }
        }
        int a = StringUtils.equals(p.getNormalStatus(), strArray[0]) ? 1 : 0;
        if (a == 0) {
            if (!StringUtils.equals(p.getNormalStatus(), strArray[1])) {
                return false;
            }
        }
        List<String> dateList = homeDataVo.getDateList();
        dateList.forEach(d -> {
            if (null == map.get(d)) {
                map.put(d, 0);
            } else {
                if (strArray[0].equals("1")) {
                    if (d.equals(DateUtil.formatDate(p.getExceptionRegisterTime()))) {
                        map.put(d, (map.get(d) + 1));
                    }
                } else if (d.equals(DateUtil.formatDate(p.getNormalTime()))) {
                    map.put(d, (map.get(d) + 1));
                }
            }
        });
        return true;
    }


    @Override
    public HomeDataVo homeData(PcuVo pcuVo) {
        String sd = pcuVo.getAreaName();
        String jw = pcuVo.getHouseNo();
        Integer pcuHomeUpdate = redisCache.getCacheObject("isPcuHomeUpdate");
        if (null != pcuHomeUpdate && 0 == pcuHomeUpdate
                && 0 != homeDataVo.getDateList().size()
                && StringUtils.isBlank(sd)
                && StringUtils.isBlank(jw)) {
            //判断是否需要更新 不需要直接返回
            Integer pcuSum = redisCache.getCacheObject("pcuSum");
            long integer = pcuMapper.selectCount(new QueryWrapper<HsPositiveContiguityUser>()
                    .in("normal_status", "1", "4", "5", "6"));
            if (integer == pcuSum) {
                return homeDataVo;
            }
        }
        //清除之前的数据
        homeDataVo.clear();
        Map<String, Integer> itemCount = homeDataVo.getItemCount();
        Map<String, List<Integer>> count = homeDataVo.getCount();
        homeDataVo.setDateList(this.getDateList(homeDataVo.getDateList()));
        List<String> dateList = homeDataVo.getDateList();
        //db中的数据
        List<HsPositiveContiguityUser> pcusDb = pcuMapper.selectList(null);
        Map<String, Integer> yangMap = new HashMap<>();
        Map<String, Integer> yinMap = new HashMap<>();
        //阳性总人数
        Long yangXSum = pcusDb.stream().filter(p -> isCount(sd, jw, p, new String[]{"1", "4"}, yangMap)).count();
        //阴性总人数
        Long yinXSum = pcusDb.stream().filter(p -> isCount(sd, jw, p, new String[]{"5", "6"}, yinMap)).count();
        itemCount.put("pcuSum", Math.toIntExact(yangXSum + yinXSum));
        itemCount.put("yangXSum", Math.toIntExact(yangXSum));
        itemCount.put("yinXSum", Math.toIntExact(yinXSum));

        List<Integer> sumList = new ArrayList<>();
        List<Integer> yangList = new ArrayList<>();
        List<Integer> yinList = new ArrayList<>();

        dateList.forEach(d -> {
            Integer integer1 = 0;
            Integer integer2 = 0;
            if (0 != yangMap.size()) {
                integer1 = yangMap.get(d);
                yangList.add(integer1);
            }
            if (0 != yinMap.size()) {
                integer2 = yinMap.get(d);
                yinList.add(integer2);
            }
            sumList.add(integer1 + integer2);
        });
        count.put("sum", sumList);
        count.put("yang", yangList);
        count.put("yin", yinList);
        redisCache.setCacheObject("isPcuHomeUpdate", 0, 1, TimeUnit.HOURS);
        redisCache.setCacheObject("pcuSum", itemCount.get("pcuSum"), 1, TimeUnit.HOURS);
        return homeDataVo;
    }

    private List<String> getDateList(List<String> dateList) {
        //获取从今天起 的上一个整月时间 yyyy-MM-dd
        for (int i = 30; i >= 1; i--) {
            DateTime registerBackDay = DateUtil.offsetDay(new Date(), -i);
            String dateStr = registerBackDay.toString("yyyy-MM-dd");
            dateList.add(dateStr);
        }
        return dateList.size() != 0 ? dateList : getDateList(dateList);
    }
}
