package com.bcxin.backend.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.bcxin.backend.configs.ScreeningConfig;
import com.bcxin.backend.dto.bg.BgScreeningParams;
import com.bcxin.backend.dto.bg.BgScreeningResultDto;
import com.bcxin.backend.entity.BgScreeningUser;
import com.bcxin.backend.entity.BgScreeningUserExecLog;
import com.bcxin.backend.entity.BgScreeningUserResult;
import com.bcxin.backend.entity.Employees;
import com.bcxin.backend.service.*;
import com.bcxin.backend.strategy.bg.BgScreeningStrategy;
import com.bcxin.backend.strategy.bg.BgScreeningStrategyFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * description: 背筛service
 * author: linchunpeng
 * date:  2023-07-13 14:30
 */
@Slf4j
@Service
public class BgScreeningServiceImpl implements BgScreeningService {

    @Autowired
    private BgScreeningUserService bgScreeningUserService;

    @Autowired
    private BgScreeningUserResultService bgScreeningUserResultService;

    @Autowired
    private BgScreeningUserExecLogService bgScreeningUserExecLogService;

    @Autowired
    private EmployeesService employeesService;

    @Autowired
    private ScreeningConfig screeningConfig;

    /**
     * description: 执行新入职背筛
     * author: linchunpeng
     * date:  2023-07-14 9:35
     */
    @Override
    @Transactional
    public void runNewRecruit() {
        //查询新入职员工列表，每次取30个(根据配置来)
        List<BgScreeningUser> newRecruitUserList = bgScreeningUserService.findNewRecruitUser(screeningConfig.getScheduled().getInductionCount());
        if (CollectionUtil.isEmpty(newRecruitUserList)) {
            log.info("执行新入职背筛，人数为0，不执行");
        } else {
            List<String> bgUserIdnumList = newRecruitUserList.stream().map(BgScreeningUser::getIdnum).collect(Collectors.toList());
            log.info("执行新入职背筛，人数：{}，身份证号码：{}", bgUserIdnumList.size(), JSONObject.toJSONString(bgUserIdnumList));
            this.runBgScreening(bgUserIdnumList);
        }
    }

    /**
     * description: 执行定期背筛
     * author: linchunpeng
     * date:  2023-07-14 9:35
     */
    @Override
    @Transactional
    public void runIntervals() {
        //查询定期背筛员工列表，每次取60个(根据配置来)
        List<BgScreeningUser> intervalsUserList = bgScreeningUserService.findIntervalsUser(screeningConfig.getScheduled().getTimingDay(),
                screeningConfig.getScheduled().getTimingCount());
        if (CollectionUtil.isEmpty(intervalsUserList)) {
            log.info("执行定期背筛，人数为0，不执行");
        } else {
            List<String> bgUserIdnumList = intervalsUserList.stream().map(BgScreeningUser::getIdnum).collect(Collectors.toList());
            log.info("执行定期背筛，人数：{}，身份证号码：{}", bgUserIdnumList.size(), JSONObject.toJSONString(bgUserIdnumList));
            this.runBgScreening(bgUserIdnumList);
        }
    }

    /**
     * description: 执行手动背筛
     * author: linchunpeng
     * date:  2023-07-14 9:35
     */
    @Override
    @Transactional
    public void runManual(List<String> bgUserIdnumList) {
        log.info("执行手动背筛，人数：{}，身份证号码：{}", bgUserIdnumList.size(), JSONObject.toJSONString(bgUserIdnumList));
        this.runBgScreening(bgUserIdnumList);

    }

    /**
     * description: 执行背筛
     * author: linchunpeng
     * date:  2023-07-14 9:40
     */
    private void runBgScreening(List<String> bgUserIdnumList) {
        BgScreeningStrategy bgScreeningStrategy = BgScreeningStrategyFactory.getBYServerKey(screeningConfig.getServerKey());
        List<BgScreeningResultDto> resultDtoList = bgScreeningStrategy.executeBgScreening(new BgScreeningParams(screeningConfig.getApi(), bgUserIdnumList));
        log.info("背筛比对完成，背筛人数：{}，比对结果数：{}", bgUserIdnumList.size(), resultDtoList.size());
        //保存背筛结果
        this.saveBgScreeningResult(resultDtoList);
    }

    /**
     * description: 保存背筛结果
     * author: linchunpeng
     * date:  2023-07-14 10:10
     */
    private void saveBgScreeningResult(List<BgScreeningResultDto> resultDtoList) {
        log.info("执行保存背筛结果");
        if (CollectionUtil.isNotEmpty(resultDtoList)) {
            Date now = new Date();
            //此次背筛产生记过的身份证列表
            List<String> resultIdnumList = resultDtoList.stream().map(BgScreeningResultDto::getIdnum).collect(Collectors.toList());
            //查询出背筛用户列表
            List<BgScreeningUser> bgScreeningUserList = bgScreeningUserService.findByIdnumList(resultIdnumList);
            log.info("需要更新的背筛用户数量：{}", bgScreeningUserList.size());
            Map<String, List<BgScreeningUser>> bgScreeningUserListMap = bgScreeningUserList.stream().collect(Collectors.groupingBy(BgScreeningUser::getIdnum));
            List<String> questionIdnumList = new ArrayList<>();
            //更新背筛结果、最近背筛时间、最后修改时间
            updateBgUserResult(resultDtoList, now, bgScreeningUserListMap, questionIdnumList);
            log.info("背筛是问题人员的数量：{}", questionIdnumList.size());
            if (CollectionUtil.isNotEmpty(questionIdnumList)) {
                //有问题
                //1、取出当前在职企业(多家)、入职时间
                List<Employees> employeesList = employeesService.findByItemDocumentIdList(questionIdnumList);
                log.info("查询出职员的数量：{}", employeesList.size());
                if (CollectionUtil.isNotEmpty(employeesList)) {
                    //根据身份证号码分组，每个身份证，可能入职多家企业
                    Map<String, List<Employees>> employeesListMap = employeesList.stream().collect(Collectors.groupingBy(Employees::getIdNo));
                    //2、查询问题表
                    Map<String, BgScreeningUserResult> existBgUserResultMap = getExistBgResultMap(questionIdnumList);
                    //更新问题记录列表，主要是：背筛次数+1
                    List<BgScreeningUserResult> updateBgResultList = new ArrayList<>();
                    //插入问题记录列表
                    List<BgScreeningUserResult> insertBgResultList = new ArrayList<>();
                    //3、循环问题列表，根据在职企业、入职时间、问题类型，判断是否有对应的问题记录
                    executeResultCompare(resultDtoList, now, employeesListMap, existBgUserResultMap, updateBgResultList, insertBgResultList);
                    //6、保存数据
                    //更新背筛问题记录表
                    log.info("更新背筛问题记录表数量：{}", updateBgResultList.size());
                    bgScreeningUserResultService.updateBatchById(updateBgResultList);
                    //新增背筛问题记录表
                    log.info("新增背筛问题记录表数量：{}", insertBgResultList.size());
                    bgScreeningUserResultService.saveBatch(insertBgResultList);
                }
            }
            //更新背筛用户表
            log.info("更新背筛用户表数量：{}", bgScreeningUserList.size());
            bgScreeningUserService.updateBatchById(bgScreeningUserList);
            //生成背筛日志
            List<BgScreeningUserExecLog> logList = new ArrayList<>();
            for (BgScreeningResultDto resultDto : resultDtoList) {
                List<BgScreeningUser> bgUserList = bgScreeningUserListMap.get(resultDto.getIdnum());
                if (CollectionUtil.isNotEmpty(bgUserList)) {
                    for (BgScreeningUser bgScreeningUser : bgUserList) {
                        logList.add(resultDto.getBgScreeningUserExecLog(now, bgScreeningUser.getPkId()));
                    }
                }
            }
            log.info("生成背筛日志数量：{}", logList.size());
            bgScreeningUserExecLogService.saveBatch(logList);
        }
    }

    /**
     * description：执行背筛结果比对
     * author：linchunpeng
     * date：2023/7/18
     */
    private void executeResultCompare(List<BgScreeningResultDto> resultDtoList, Date now,
                                      Map<String, List<Employees>> employeesListMap,
                                      Map<String, BgScreeningUserResult> existBgUserResultMap,
                                      List<BgScreeningUserResult> updateBgResultList,
                                      List<BgScreeningUserResult> insertBgResultList) {
        log.info("执行结果比对");
        for (BgScreeningResultDto resultDto : resultDtoList) {
            if (CollectionUtil.isNotEmpty(resultDto.getQuestionType())) {
                //背筛问题类型列不为控
                log.info("身份证号码：{}，背筛问题类型：{}", resultDto.getIdnum(), resultDto.getQuestionType());
                //取出身份证所有的在职公司列表
                List<Employees> employeesList = employeesListMap.get(resultDto.getIdnum());
                log.info("身份证号码：{}，职员表数量：{}", resultDto.getIdnum(), employeesList == null ? 0 : employeesList.size());
                if (CollectionUtil.isNotEmpty(employeesList)) {
                    //循环问题列表
                    for (Integer questionType : resultDto.getQuestionType()) {
                        //循环在职公司列表
                        for (Employees employees : employeesList) {
                            String key =  getQuestionMapKey(resultDto.getIdnum(), employees.getItemDomainId(), questionType.toString());
                            //从问题记录里面取出：当前身份证、当前公司、当前问题类型，的问题记录
                            BgScreeningUserResult userResult = existBgUserResultMap.get(key);
                            //不为空，说明存在，则需要判断记录是不是则入职日期之后
                            if (userResult != null && employees.getHireDate() != null && userResult.getCreated().after(employees.getHireDate())) {
                                //在入职之后，说明不需要新增记录了，只需要：背筛次数+1
                                log.info("身份证号码：{}，已存在入职之后的问题类型，只需要：背筛次数+1", resultDto.getIdnum());
                                int oldCount = userResult.getScreeningCount() == null ? 1 : userResult.getScreeningCount();
                                userResult.setScreeningCount(oldCount+1);
                                if (StringUtils.isBlank(userResult.getRegisterPoliceAddressId())) {
                                    //如果原记录的监管归属为空，则重新设置
                                    userResult.setRegisterPoliceAddress(employees.getSuperviseOffice());
                                    userResult.setRegisterPoliceAddressId(employees.getSuperviseOfficeCode());
                                }
                                updateBgResultList.add(userResult);
                            } else {
                                //没有记录 || 记录在入职之前的，需要新增问题记录
                                log.info("身份证号码：{}，没有记录 || 记录在入职之前，需要新增问题记录", resultDto.getIdnum());
                                insertBgResultList.add(createNewBgResult(now, resultDto, questionType, employees));
                            }
                        }
                    }
                }
            }
        }
        log.info("执行结果比对结束");
    }

    /**
     * description：获取已存在的问题列表
     * author：linchunpeng
     * date：2023/7/18
     */
    private Map<String, BgScreeningUserResult> getExistBgResultMap(List<String> questionIdnumList) {
        Map<String, BgScreeningUserResult> bgUserResultMap = new HashMap<>();
        List<BgScreeningUserResult> bgUserResultList = bgScreeningUserResultService.findByIdnumList(questionIdnumList);
        log.info("查询出已存在的问题列表的数量：{}", bgUserResultList.size());
        if (CollectionUtil.isNotEmpty(bgUserResultList)) {
            for (BgScreeningUserResult bgUserResult : bgUserResultList) {
                String key =  getQuestionMapKey(bgUserResult.getDocumentId(), bgUserResult.getCompanyId(), bgUserResult.getType().toString());
                bgUserResultMap.put(key, bgUserResult);
            }
        }
        return bgUserResultMap;
    }

    /**
     * description：新增问题记录
     * author：linchunpeng
     * date：2023/7/18
     */
    private BgScreeningUserResult createNewBgResult(Date now, BgScreeningResultDto resultDto, Integer questionType,
                                                    Employees employees) {
        BgScreeningUserResult bgScreeningUserResult = new BgScreeningUserResult();
        bgScreeningUserResult.setId(UUID.randomUUID().toString());
        bgScreeningUserResult.setType(questionType);
        bgScreeningUserResult.setCreated(now);
        bgScreeningUserResult.setLastModified(now);
        bgScreeningUserResult.setFirstCompareTime(now);
        bgScreeningUserResult.setCompareTime(now);
        bgScreeningUserResult.setDomainId(employees.getDomainId());
        bgScreeningUserResult.setQuestionType(resultDto.getProblemDetail());
        bgScreeningUserResult.setUserId(employees.getUserId());
        bgScreeningUserResult.setSecurityName(employees.getName());
        bgScreeningUserResult.setDocumentId(resultDto.getIdnum());
        bgScreeningUserResult.setPhone(employees.getPhone());
        bgScreeningUserResult.setCompanyName(employees.getCompanyName());
        bgScreeningUserResult.setCompanyId(employees.getItemDomainId());
        bgScreeningUserResult.setRegisterPoliceAddress(employees.getSuperviseOffice());
        bgScreeningUserResult.setRegisterPoliceAddressId(employees.getSuperviseOfficeCode());
        bgScreeningUserResult.setPoliceStatus("0");
        bgScreeningUserResult.setWorkStatus("1");
        bgScreeningUserResult.setCompanyStatus("0");
        bgScreeningUserResult.setEntryTime(employees.getHireDate());
        bgScreeningUserResult.setCaptureStatus(questionType == 1 ? 0 : null);
        bgScreeningUserResult.setScreeningCount(1);
        return bgScreeningUserResult;
    }

    /**
     * description：更新背筛结果、最近背筛时间、最后修改时间
     * author：linchunpeng
     * date：2023/7/18
     */
    private void updateBgUserResult(List<BgScreeningResultDto> resultDtoList, Date now, Map<String, List<BgScreeningUser>> bgScreeningUserListMap, List<String> questionIdnumList) {
        for (BgScreeningResultDto resultDto : resultDtoList) {
            if (resultDto.getIsProblem()) {
                //是问题人员
                questionIdnumList.add(resultDto.getIdnum());
            }
            List<BgScreeningUser> bgScreeningUserList = bgScreeningUserListMap.get(resultDto.getIdnum());
            if (CollectionUtil.isNotEmpty(bgScreeningUserList)) {
                for (BgScreeningUser bgScreeningUser : bgScreeningUserList) {
                    bgScreeningUser.setBackgroundScreeningStatus(resultDto.getBgStatus());
                    bgScreeningUser.setLastBackgroundScreeningTime(now);
                    bgScreeningUser.setLastBgScreeningResultStatus(resultDto.getBgResultType());
                    bgScreeningUser.setLastBgScreeningResult(resultDto.getBgResult());
                    bgScreeningUser.setLastModifiedTime(now);
                }
            }
        }
    }

    /**
     * description：问题表的key
     * author：linchunpeng
     * date：2023/7/18
     */
    private String getQuestionMapKey(String idnum, String companyId, String questionType) {
        return idnum.concat("-").concat(companyId).concat("-").concat(questionType);
    }
}
