package com.hz.pm.api.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.hz.pm.api.common.model.constant.BizConst;
import com.hz.pm.api.ding.constants.DingOrganizationContant;
import com.hz.pm.api.organization.model.entity.DingEmployeeInfo;
import com.hz.pm.api.organization.model.entity.DingOrganization;
import com.hz.pm.api.organization.service.IDingEmployeeInfoService;
import com.hz.pm.api.organization.service.IDingOrganizationService;
import com.hz.pm.api.user.model.entity.UserInfo;
import com.hz.pm.api.user.service.IUserInfoService;
import com.ningdatech.basic.function.VUtils;
import com.ningdatech.basic.model.GenericResult;
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.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
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
 */

@Slf4j
@Component
@RequiredArgsConstructor
public class EmployeeBatchGetTask {

    private static final int PAGE_SIZE = 20;
    private static final int GROUP_SIZE = 100;
    private static final long MAX_SIZE = 10000;

    //==================================================================================================================

    private final ZwddClient zwddClient;
    private final ZwddAuthClient zwddAuthClient;
    private final IDingOrganizationService dingOrganizationService;
    private final IDingEmployeeInfoService dingEmployeeInfoService;
    private final ZwddIntegrationProperties zwddIntegrationProperties;
    private final IUserInfoService userInfoService;

    //==================================================================================================================

    @Transactional(rollbackFor = Exception.class)
    // @Scheduled(cron = "0 0 1 * * ?")
    public void batchGetEmployeeTask() {
        // 获取所有的组织列表用户获取组织下的 用户信息(暂时只查单位的类型)
        List<DingOrganization> dingOrganizationList = dingOrganizationService.list(
                Wrappers.lambdaQuery(DingOrganization.class)
                        .eq(DingOrganization::getTypeCode, DingOrganizationContant.UNIT_TYPE));
        log.info("所有待更新员工的单位数:{}", dingOrganizationList.size());
        if (CollUtil.isNotEmpty(dingOrganizationList)) {
            //记录任务 单位数
            Integer index = 0;
            for (DingOrganization dingOrg : dingOrganizationList) {
                log.info("当前单位:{},下标数,{}", dingOrg.getOrganizationName(), index);
                index++;
                List<OrganizationEmployeePosition> allOrganizationEmployeePositionList = new ArrayList<>();
                String organizationCode = dingOrg.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("dingOrg :{}", JSON.toJSONString(dingOrg));

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

                    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);
                        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 = dingOrganizationService.list();
        Map<String, DingOrganization> organizationMap = organizations.stream().collect(Collectors.toMap(DingOrganization::getOrganizationCode, o -> o));

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

            DingEmployeeInfo employeeInfo = dingEmployeeInfoService.getOne(Wrappers.lambdaQuery(DingEmployeeInfo.class)
                    .eq(DingEmployeeInfo::getEmployeeCode, employeeCode)
                    .last(BizConst.LIMIT_1));
            if (Objects.isNull(employeeInfo)) {
                dingEmployeeInfoService.save(dingEmployeeInfo);
            } else {
                dingEmployeeInfo.setId(employeeInfo.getId());
                dingEmployeeInfoService.saveOrUpdate(dingEmployeeInfo);
            }
        }
    }

    /**
     * 按区域 来更新员工
     *
     * @param regionCode
     */
    public void batchGetEmployeeTaskByRegionCode(String regionCode) {
        List<DingOrganization> units = dingOrganizationService.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;
                    }

                    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);
                        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 = dingOrganizationService.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<>();
        PageOrganizationEmployeePositionsQuery query = new PageOrganizationEmployeePositionsQuery();
        query.setEmployeeStatus("A");
        query.setOrganizationCode(orgCode);
        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("响应为空:{}", orgCode);
            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;
            }

            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 = dingEmployeeInfoService.getOne(Wrappers.lambdaQuery(DingEmployeeInfo.class)
                .eq(DingEmployeeInfo::getEmployeeCode, empCode)
                .last(BizConst.LIMIT_1));

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

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

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

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

        List<DingEmployeeInfo> employees = dingEmployeeInfoService.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();
    }
}
