package com.ningdatech.pmapi.ding.task;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.ningdatech.basic.function.VUtils;
import com.ningdatech.basic.model.GenericResult;
import com.ningdatech.pmapi.common.constant.BizConst;
import com.ningdatech.pmapi.ding.constants.DingOrganizationContant;
import com.ningdatech.pmapi.organization.model.entity.DingEmployeeInfo;
import com.ningdatech.pmapi.organization.model.entity.DingOrganization;
import com.ningdatech.pmapi.organization.service.IDingEmployeeInfoService;
import com.ningdatech.pmapi.organization.service.IDingOrganizationService;
import com.ningdatech.pmapi.user.constant.UserAvailableEnum;
import com.ningdatech.pmapi.user.entity.UserInfo;
import com.ningdatech.pmapi.user.service.IUserInfoService;
import com.ningdatech.zwdd.ZwddIntegrationProperties;
import com.ningdatech.zwdd.client.ZwddAuthClient;
import com.ningdatech.zwdd.client.ZwddClient;
import com.ningdatech.zwdd.model.Page;
import com.ningdatech.zwdd.model.dto.EmployeeAccountIdDTO;
import com.ningdatech.zwdd.model.dto.EmployeeInfoDTO;
import com.ningdatech.zwdd.model.query.PageOrganizationEmployeePositionsQuery;
import com.ningdatech.zwdd.model.response.OrganizationEmployeePosition;
import com.ningdatech.zwdd.model.response.OrganizationEmployeePosition.GovEmployeePosition;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * @author liuxinxin
 * @date 2023/2/10 上午9:52
 */

@Component
@Slf4j
public class EmployeeBatchGetTask {

    private final static Integer PAGE_SIZE = 20;

    private final static Integer GROUP_SIZE = 100;

    private final static Integer MAX_SIZE = 10000;

    @Autowired
    private ZwddClient zwddClient;

    @Autowired
    private ZwddAuthClient zwddAuthClient;

    @Autowired
    private IDingOrganizationService iDingOrganizationService;

    @Autowired
    private IDingEmployeeInfoService iDingEmployeeInfoService;

    @Autowired
    private ZwddIntegrationProperties zwddIntegrationProperties;

    @Autowired
    private IUserInfoService iUserInfoService;

    @Transactional(rollbackFor = Exception.class)
//    @Scheduled(cron = "0 0 1 * * ?")
    public void batchGetEmployeeTask() {
        // 获取所有的组织列表用户获取组织下的 用户信息(暂时 只查 单位的类型)
        List<DingOrganization> dingOrganizationList = iDingOrganizationService.list(Wrappers.lambdaQuery(DingOrganization.class)
                .eq(DingOrganization::getTypeCode, DingOrganizationContant.UNIT_TYPE));
        log.info("所有待更新员工的单位数:{}",dingOrganizationList.size());
        if (CollUtil.isNotEmpty(dingOrganizationList)) {
            //记录任务 单位数
            Integer index = 0;
            for (DingOrganization dingOrganization : dingOrganizationList) {
                log.info("当前单位:{},下标数,{}",dingOrganization.getOrganizationName(),index);
                index++;
                List<OrganizationEmployeePosition> allOrganizationEmployeePositionList = new ArrayList<>();
                String organizationCode = dingOrganization.getOrganizationCode();
                PageOrganizationEmployeePositionsQuery query = new PageOrganizationEmployeePositionsQuery();
                query.setEmployeeStatus("A");
                query.setOrganizationCode(organizationCode);
                query.setReturnTotalSize(true);
                query.setTenantId(zwddIntegrationProperties.getTenantId());
                int pageNo = 1;
                query.setPageNo(pageNo);
                query.setPageSize(PAGE_SIZE);

                // 查询组织下 用户信息
                GenericResult<Page<OrganizationEmployeePosition>> firstPageGenericResult = zwddClient.pageOrganizationEmployeePositions(query);
                Page<OrganizationEmployeePosition> data = firstPageGenericResult.getData();
                if (Objects.isNull(data)){
                    log.info("响应为空:{}",organizationCode);
                    continue;
                }
                if (CollUtil.isNotEmpty(data.getData())) {
                    allOrganizationEmployeePositionList.addAll(data.getData());
                }
                Long totalSize = data.getTotalSize();

                log.info("dingOrganization :{}", JSON.toJSONString(dingOrganization));

                log.info("totalSize :{},{}", totalSize,dingOrganization.getOrganizationName());
                if (totalSize > PAGE_SIZE) {
                    if (totalSize > MAX_SIZE) {
                        //超过1万 按1万的处理
                        totalSize = MAX_SIZE.longValue();
                    }

                    int restPageNo = totalSize % PAGE_SIZE > 0 ? 1 : 0;
                    int maxPageNo = (int) Math.ceil(totalSize / PAGE_SIZE) + restPageNo;
                    for (pageNo = 2; pageNo <= maxPageNo; pageNo++) {
                        query.setPageNo(pageNo);
                        GenericResult<Page<OrganizationEmployeePosition>> pageGenericResult = zwddClient.pageOrganizationEmployeePositions(query);
//                        log.info("pageGenericResult :{}", JSON.toJSONString(pageGenericResult));
                        if(pageGenericResult.isSuccess()){
                            allOrganizationEmployeePositionList.addAll(pageGenericResult.getData().getData());
                        }else{
                            log.error(pageGenericResult.getMsg());
                        }
                    }
                }

                // 批量查询 成员的accountId
                List<DingEmployeeInfo> dingEmployeeInfoSaveRecordList = new ArrayList<>();
                if (allOrganizationEmployeePositionList.size() <= GROUP_SIZE) {
                    log.info("assemblerAccountId :{}", allOrganizationEmployeePositionList.size());
                    assemblerAccountId(allOrganizationEmployeePositionList, dingEmployeeInfoSaveRecordList);
                } else {
                    log.info("assemblerAccountId :{}", allOrganizationEmployeePositionList.size());
                    List<List<OrganizationEmployeePosition>> split = Lists.partition(allOrganizationEmployeePositionList, GROUP_SIZE);
                    for (List<OrganizationEmployeePosition> segment : split) {
                        assemblerAccountId(segment, dingEmployeeInfoSaveRecordList);
                    }
                }
                // 批量保存用户信息
                saveBatch(dingEmployeeInfoSaveRecordList);
            }
        }
    }


    private void assemblerAccountId(List<OrganizationEmployeePosition> segment, List<DingEmployeeInfo> dingEmployeeInfoSaveRecordList) {
        List<String> employeeCodes = segment.stream().map(OrganizationEmployeePosition::getEmployeeCode).distinct().collect(Collectors.toList());
        GenericResult<List<EmployeeAccountIdDTO>> listGenericResult = zwddClient.listEmployeeAccountIds(employeeCodes);
        List<EmployeeAccountIdDTO> employeeAccountIdDTOList = listGenericResult.getData();
        if (CollUtil.isNotEmpty(employeeAccountIdDTOList)) {
            Map<String, Long> employeeCodeAccountIdMap = employeeAccountIdDTOList.stream().filter(Objects::nonNull)
                    .collect(Collectors.toMap(EmployeeAccountIdDTO::getEmployeeCode, EmployeeAccountIdDTO::getAccountId));

            List<DingEmployeeInfo> dingEmployeeInfos = buildDingEmployeeInfoRecordList(segment);

            dingEmployeeInfos = dingEmployeeInfos.stream().map(r -> {
                r.setAccountId(employeeCodeAccountIdMap.get(r.getEmployeeCode()));
                return r;
            }).collect(Collectors.toList());
            dingEmployeeInfoSaveRecordList.addAll(dingEmployeeInfos);
        }
    }

    private List<DingEmployeeInfo> buildDingEmployeeInfoRecordList(List<OrganizationEmployeePosition> allOrganizationEmployeePositionList) {
        List<DingEmployeeInfo> saveRecordList = new ArrayList<>();
        for (OrganizationEmployeePosition organizationEmployeePosition : allOrganizationEmployeePositionList) {
            List<GovEmployeePosition> govEmployeePositions = organizationEmployeePosition.getGovEmployeePositions();
            if (CollUtil.isNotEmpty(govEmployeePositions)) {
                List<DingEmployeeInfo> segmentSaveRecordList = new ArrayList<>();
                for (GovEmployeePosition govEmployeePosition : govEmployeePositions) {
                    DingEmployeeInfo dingEmployeeInfo = new DingEmployeeInfo();
                    BeanUtils.copyProperties(organizationEmployeePosition, dingEmployeeInfo);
                    dingEmployeeInfo.setMainJob(govEmployeePosition.getMainJob());
                    dingEmployeeInfo.setEmpPosUnitCode(govEmployeePosition.getEmpPosUnitCode());
                    dingEmployeeInfo.setEmpPosEmployeeRoleCode(govEmployeePosition.getEmpPosEmployeeRoleCode());
                    dingEmployeeInfo.setEmpPosInnerInstitutionCode(govEmployeePosition.getEmpPosInnerInstitutionCode());
                    dingEmployeeInfo.setEmployeeCode(govEmployeePosition.getEmployeeCode());
                    dingEmployeeInfo.setJobAttributesCode(govEmployeePosition.getJobAttributesCode());
                    dingEmployeeInfo.setOrganizationCode(govEmployeePosition.getOrganizationCode());
                    dingEmployeeInfo.setEmpPosVirtualOrganizationCode(govEmployeePosition.getEmpPosVirtualOrganizationCode());
                    dingEmployeeInfo.setEmpStatus(govEmployeePosition.getStatus());
                    dingEmployeeInfo.setCreateOn(LocalDateTime.now());
                    dingEmployeeInfo.setUpdateOn(LocalDateTime.now());
                    dingEmployeeInfo.setCreateBy(-1L);
                    dingEmployeeInfo.setUpdateBy(-1L);
                    segmentSaveRecordList.add(dingEmployeeInfo);
                }
                saveRecordList.addAll(segmentSaveRecordList);
            } else {
                DingEmployeeInfo dingEmployeeInfo = new DingEmployeeInfo();
                BeanUtils.copyProperties(organizationEmployeePosition, dingEmployeeInfo);
                saveRecordList.add(dingEmployeeInfo);
            }
        }
        return saveRecordList;
    }

    private void saveBatch(List<DingEmployeeInfo> dingEmployeeInfoSaveRecordList) {
        dingEmployeeInfoSaveRecordList = dingEmployeeInfoSaveRecordList.stream()
                .filter(r -> "true".equals(r.getMainJob())
                        && "A".equals(r.getEmpStatus())
                        && StringUtils.isNotBlank(r.getEmpPosUnitCode())
                        && StringUtils.isNotBlank(r.getEmployeeCode())
                ).collect(Collectors.toList());

        Set<String> uniqueKeySet = new HashSet<String>();

        List<DingEmployeeInfo> saveList = new ArrayList<>();

        for (DingEmployeeInfo dingEmployeeInfo : dingEmployeeInfoSaveRecordList) {
            if (uniqueKeySet.add(dingEmployeeInfo.getEmployeeCode() + dingEmployeeInfo.getEmpPosUnitCode())) {
                saveList.add(dingEmployeeInfo);
            }
        }

        List<DingOrganization> organizations = iDingOrganizationService.list();
        Map<String, DingOrganization> organizationMap = organizations.stream().collect(Collectors.toMap(DingOrganization::getOrganizationCode, o -> o));

        for (DingEmployeeInfo dingEmployeeInfo : saveList) {
            String employeeCode = dingEmployeeInfo.getEmployeeCode();

            DingEmployeeInfo employeeInfo = iDingEmployeeInfoService.getOne(Wrappers.lambdaQuery(DingEmployeeInfo.class)
                    .eq(DingEmployeeInfo::getEmpPosUnitCode, dingEmployeeInfo.getEmpPosUnitCode())
                    .eq(DingEmployeeInfo::getEmployeeCode, employeeCode));
            if (Objects.isNull(employeeInfo)) {
                iDingEmployeeInfoService.save(dingEmployeeInfo);
            } else {
                dingEmployeeInfo.setId(employeeInfo.getId());
                iDingEmployeeInfoService.saveOrUpdate(dingEmployeeInfo);
            }
            generateOrUpdateUserInfo(dingEmployeeInfo,organizationMap);
        }
    }

    public void generateOrUpdateUserInfo(DingEmployeeInfo dingEmployeeInfo,Map<String, DingOrganization> organizationMap) {
        String employeeCode = dingEmployeeInfo.getEmployeeCode();
        UserInfo userInfo = iUserInfoService.getOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getEmployeeCode, employeeCode));
        if (Objects.isNull(userInfo)) {
            userInfo = UserInfo.builder()
                    .accountId(dingEmployeeInfo.getAccountId())
                    .username(dingEmployeeInfo.getEmployeeName())
                    .realName(dingEmployeeInfo.getEmployeeName())
                    .employeeCode(dingEmployeeInfo.getEmployeeCode())
                    .available(UserAvailableEnum.DISABLE.name())
                    .createBy(-1L)
                    .updateBy(-1L)
                    .createOn(LocalDateTime.now())
                    .updateOn(LocalDateTime.now())
                    .empPosUnitCode(dingEmployeeInfo.getEmpPosUnitCode())
                    .avatar(dingEmployeeInfo.getAvatar())
                    .build();
            if(StringUtils.isNotBlank(userInfo.getEmpPosUnitCode()) && organizationMap.containsKey(userInfo.getEmpPosUnitCode())){
                DingOrganization dingOrganization = organizationMap.get(userInfo.getEmpPosUnitCode());
                userInfo.setEmpPosUnitName(dingOrganization.getOrganizationName());
                userInfo.setRegionCode(dingOrganization.getDivisionCode());
            }
            iUserInfoService.save(userInfo);
        }else{
            userInfo.setAvatar(dingEmployeeInfo.getAvatar());
            iUserInfoService.updateById(userInfo);
        }
    }

    /**
     * 按区域 来更新员工
     * @param regionCode
     */
    public void batchGetEmployeeTaskByRegionCode(String regionCode) {
        List<DingOrganization> units = iDingOrganizationService.list(Wrappers.lambdaQuery(DingOrganization.class)
                .eq(DingOrganization::getTypeCode, DingOrganizationContant.UNIT_TYPE)
                .eq(DingOrganization::getDivisionCode, regionCode));


        log.info("所有地区 {} 待更新员工的单位数:{}",regionCode,units.size());
        if (CollUtil.isNotEmpty(units)) {
            //记录任务 单位数
            Integer index = 0;
            for (DingOrganization dingOrganization : units) {
                log.info("当前单位:{},下标数,{}",dingOrganization.getOrganizationName(),index);
                index++;
                List<OrganizationEmployeePosition> allOrganizationEmployeePositionList = new ArrayList<>();
                String organizationCode = dingOrganization.getOrganizationCode();
                PageOrganizationEmployeePositionsQuery query = new PageOrganizationEmployeePositionsQuery();
                query.setEmployeeStatus("A");
                query.setOrganizationCode(organizationCode);
                query.setReturnTotalSize(true);
                query.setTenantId(zwddIntegrationProperties.getTenantId());
                int pageNo = 1;
                query.setPageNo(pageNo);
                query.setPageSize(PAGE_SIZE);

                // 查询组织下 用户信息
                GenericResult<Page<OrganizationEmployeePosition>> firstPageGenericResult = zwddClient.pageOrganizationEmployeePositions(query);
                Page<OrganizationEmployeePosition> data = firstPageGenericResult.getData();
                if (Objects.isNull(data)){
                    log.info("响应为空:{}",organizationCode);
                    continue;
                }
                if (CollUtil.isNotEmpty(data.getData())) {
                    allOrganizationEmployeePositionList.addAll(data.getData());
                }
                Long totalSize = data.getTotalSize();

                log.info("dingOrganization :{}", JSON.toJSONString(dingOrganization));

                log.info("totalSize :{},{}", totalSize,dingOrganization.getOrganizationName());
                if (totalSize > PAGE_SIZE) {
                    if (totalSize > MAX_SIZE) {
                        //超过1万 按1万的处理
                        totalSize = MAX_SIZE.longValue();
                    }

                    int restPageNo = totalSize % PAGE_SIZE > 0 ? 1 : 0;
                    int maxPageNo = (int) Math.ceil(totalSize / PAGE_SIZE) + restPageNo;
                    for (pageNo = 2; pageNo <= maxPageNo; pageNo++) {
                        query.setPageNo(pageNo);
                        GenericResult<Page<OrganizationEmployeePosition>> pageGenericResult = zwddClient.pageOrganizationEmployeePositions(query);
//                        log.info("pageGenericResult :{}", JSON.toJSONString(pageGenericResult));
                        if(pageGenericResult.isSuccess()){
                            allOrganizationEmployeePositionList.addAll(pageGenericResult.getData().getData());
                        }else{
                            log.error(pageGenericResult.getMsg());
                        }
                    }
                }

                // 批量查询 成员的accountId
                List<DingEmployeeInfo> dingEmployeeInfoSaveRecordList = new ArrayList<>();
                if (allOrganizationEmployeePositionList.size() <= GROUP_SIZE) {
                    log.info("assemblerAccountId :{}", allOrganizationEmployeePositionList.size());
                    assemblerAccountId(allOrganizationEmployeePositionList, dingEmployeeInfoSaveRecordList);
                } else {
                    log.info("assemblerAccountId :{}", allOrganizationEmployeePositionList.size());
                    List<List<OrganizationEmployeePosition>> split = Lists.partition(allOrganizationEmployeePositionList, GROUP_SIZE);
                    for (List<OrganizationEmployeePosition> segment : split) {
                        assemblerAccountId(segment, dingEmployeeInfoSaveRecordList);
                    }
                }
                // 批量保存用户信息
                saveBatch(dingEmployeeInfoSaveRecordList);
            }
            log.info("员工同步完成");
        }
    }

    public void batchGetEmployeeTaskByOrdCode(String orgCode) {
        DingOrganization org = iDingOrganizationService.getOne(Wrappers.lambdaQuery(DingOrganization.class)
                .eq(DingOrganization::getOrganizationCode, orgCode)
                .last(BizConst.LIMIT_1));
        VUtils.isTrue(Objects.isNull(org)).throwMessage("单位不存在");
        log.info("所属单位 {} 要更新员工信息了",org.getOrganizationName());

        List<OrganizationEmployeePosition> allOrganizationEmployeePositionList = new ArrayList<>();
        String organizationCode = orgCode;
        PageOrganizationEmployeePositionsQuery query = new PageOrganizationEmployeePositionsQuery();
        query.setEmployeeStatus("A");
        query.setOrganizationCode(organizationCode);
        query.setReturnTotalSize(true);
        query.setTenantId(zwddIntegrationProperties.getTenantId());
        int pageNo = 1;
        query.setPageNo(pageNo);
        query.setPageSize(PAGE_SIZE);

        // 查询组织下 用户信息
        GenericResult<Page<OrganizationEmployeePosition>> firstPageGenericResult = zwddClient.pageOrganizationEmployeePositions(query);
        Page<OrganizationEmployeePosition> data = firstPageGenericResult.getData();
        if (Objects.isNull(data)){
            log.info("响应为空:{}",organizationCode);
            return;
        }
        if (CollUtil.isNotEmpty(data.getData())) {
            allOrganizationEmployeePositionList.addAll(data.getData());
        }
        Long totalSize = data.getTotalSize();

        log.info("dingOrganization :{}", JSON.toJSONString(org));

        log.info("totalSize :{},{}", totalSize,org.getOrganizationName());
        if (totalSize > PAGE_SIZE) {
            if (totalSize > MAX_SIZE) {
                //超过1万 按1万的处理
                totalSize = MAX_SIZE.longValue();
            }

            int restPageNo = totalSize % PAGE_SIZE > 0 ? 1 : 0;
            int maxPageNo = (int) Math.ceil(totalSize / PAGE_SIZE) + restPageNo;
            for (pageNo = 2; pageNo <= maxPageNo; pageNo++) {
                query.setPageNo(pageNo);
                GenericResult<Page<OrganizationEmployeePosition>> pageGenericResult = zwddClient.pageOrganizationEmployeePositions(query);
//                        log.info("pageGenericResult :{}", JSON.toJSONString(pageGenericResult));
                if(pageGenericResult.isSuccess()){
                    allOrganizationEmployeePositionList.addAll(pageGenericResult.getData().getData());
                }else{
                    log.error(pageGenericResult.getMsg());
                }
            }
        }

        // 批量查询 成员的accountId
        List<DingEmployeeInfo> dingEmployeeInfoSaveRecordList = new ArrayList<>();
        if (allOrganizationEmployeePositionList.size() <= GROUP_SIZE) {
            log.info("assemblerAccountId :{}", allOrganizationEmployeePositionList.size());
            assemblerAccountId(allOrganizationEmployeePositionList, dingEmployeeInfoSaveRecordList);
        } else {
            log.info("assemblerAccountId :{}", allOrganizationEmployeePositionList.size());
            List<List<OrganizationEmployeePosition>> split = Lists.partition(allOrganizationEmployeePositionList, GROUP_SIZE);
            for (List<OrganizationEmployeePosition> segment : split) {
                assemblerAccountId(segment, dingEmployeeInfoSaveRecordList);
            }
        }
        // 批量保存用户信息
        saveBatch(dingEmployeeInfoSaveRecordList);

        log.info("员工同步完成");

    }

    /**
     * 更新员工信息 主要是头像
     * @param empCode
     */
    public void getEmployeeByCode(String empCode) {
        GenericResult<EmployeeInfoDTO> result = zwddClient.getEmployeeByCode(empCode);
        log.error("请求员工信息 result:{}",JSON.toJSONString(result));
        if(!result.isSuccess()){
            log.error("请求员工信息失败 :{},mesg:{}",empCode,result.getMsg());
            return;
        }
        EmployeeInfoDTO data = result.getData();

        if(Objects.isNull(data)){
            log.error("请求员工信息失败 返回为空");
            return;
        }

        DingEmployeeInfo emp = iDingEmployeeInfoService.getOne(Wrappers.lambdaQuery(DingEmployeeInfo.class)
                .eq(DingEmployeeInfo::getEmployeeCode, empCode)
                .last(BizConst.LIMIT_1));

        if(Objects.nonNull(emp)){
            emp.setAvatar(data.getGovEmpAvatar());
            iDingEmployeeInfoService.updateById(emp);
        }

        UserInfo user = iUserInfoService.getOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getEmployeeCode, empCode)
                .last(BizConst.LIMIT_1));

        if(Objects.nonNull(user)){
            user.setAvatar(data.getGovEmpAvatar());
            iUserInfoService.updateById(user);
        }
    }

    /**
     * 更新一整个单位的
     * @param orgCode
     */
    public void getBatchEmployeeByCode(String orgCode) {

        List<DingEmployeeInfo> employees = iDingEmployeeInfoService.list(Wrappers.lambdaQuery(DingEmployeeInfo.class)
                .eq(DingEmployeeInfo::getEmpPosUnitCode, orgCode));

        for(DingEmployeeInfo employee :  employees){
            getEmployeeByCode(employee.getEmployeeCode());
        }
    }

    /**
     * 获取token
     */
    public String getToken() {
        GenericResult<String> accessToken = zwddClient.getAccessToken();
        return accessToken.getData();
    }

    public String getAuthToken() {
        GenericResult<String> accessToken = zwddAuthClient.getAccessToken();
        return accessToken.getData();
    }
}
