package com.hz.pm.api.user.manage;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.PhoneUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hz.pm.api.common.util.BizUtils;
import com.hz.pm.api.expert.entity.ExpertUserFullInfo;
import com.hz.pm.api.expert.service.IExpertUserFullInfoService;
import com.hz.pm.api.external.MhApiClient;
import com.hz.pm.api.external.model.dto.*;
import com.hz.pm.api.meta.helper.DictionaryCache;
import com.hz.pm.api.meta.model.dto.DictionaryDTO;
import com.hz.pm.api.meta.model.entity.ExpertDictionary;
import com.hz.pm.api.meta.service.IExpertDictionaryService;
import com.hz.pm.api.user.model.entity.MhCompany;
import com.hz.pm.api.user.model.entity.MhUnit;
import com.hz.pm.api.user.model.entity.UserInfo;
import com.hz.pm.api.user.model.enumeration.UserAvailableEnum;
import com.hz.pm.api.user.service.IMhCompanyService;
import com.hz.pm.api.user.service.IMhUnitService;
import com.hz.pm.api.user.service.IUserInfoService;
import com.hz.pm.api.user.task.SyncMhUserProperties;
import com.ningdatech.basic.util.CollUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static com.hz.pm.api.meta.constant.ExpertDictTypeEnum.*;

/**
 * <p>
 * SyncMhUserManage
 * </p>
 *
 * @author WendyYang
 * @since 11:54 2023/12/25
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class SyncMhUserOrgManage {

    private final IExpertUserFullInfoService expertUserFullInfoService;
    private final IUserInfoService userInfoService;
    private final MhApiClient mhApiClient;
    private final SyncMhUserProperties syncMhUserProperties;
    private final IMhUnitService mhUnitService;
    private final IMhCompanyService mhCompanyService;
    private final DictionaryCache dictionaryCache;
    private final IExpertDictionaryService expertDictionaryService;

    public void syncUsers(LocalDateTime syncDateTime) {
        MhRetDTO<List<MhUserDTO>> mhRet = mhApiClient.queryUsers(syncDateTime);
        if (mhRet.isOk()) {
            List<MhUserDTO> mhUsers = mhRet.getData();
            if (CollUtil.isEmpty(mhUsers)) {
                return;
            }
            List<MhUnit> units = mhUnitService.list();
            Map<Long, MhUnit> unitMap = CollUtils.listToMap(units, MhUnit::getId);
            Integer batchSize = syncMhUserProperties.getBatchSize();
            List<List<MhUserDTO>> mhUserParts = ListUtil.partition(mhUsers, batchSize);
            for (List<MhUserDTO> part : mhUserParts) {
                List<String> mhUserIds = CollUtils.fieldList(part, MhUserDTO::getUserId);
                Map<String, Long> userIdMap = userInfoService.listUserIdByMhUserIds(mhUserIds);
                List<UserInfo> savedList = new ArrayList<>();
                for (MhUserDTO mhUser : part) {
                    if (StrUtil.isBlank(mhUser.getUserId())) {
                        continue;
                    }
                    UserInfo userInfo = new UserInfo();
                    userInfo.setMhUserId(mhUser.getUserId());
                    if (Boolean.TRUE.equals(mhUser.getIsZzdAccount())
                            && (NumberUtil.isNumber(mhUser.getAccountId()))) {
                        userInfo.setAccountId(Long.parseLong(mhUser.getAccountId()));
                    }
                    UserAvailableEnum userStatus = getUserAvailable(mhUser.getStatus());
                    userInfo.setAvailable(userStatus.name());
                    userInfo.setRealName(mhUser.getUserName());
                    userInfo.setUsername(mhUser.getAccount());
                    userInfo.setId(userIdMap.get(mhUser.getUserId()));
                    MhUnit unit = unitMap.get(mhUser.getMhUnitId());
                    if (unit != null) {
                        userInfo.setMhUnitName(unit.getName());
                    }
                    if (PhoneUtil.isMobile(mhUser.getAccount())) {
                        userInfo.setMobile(mhUser.getAccount());
                    }
                    userInfo.setMhUnitId(mhUser.getMhUnitId());
                    savedList.add(userInfo);
                }
                if (!savedList.isEmpty()) {
                    log.info("同步用户数量：{}", savedList.size());
                    userInfoService.saveOrUpdateBatch(savedList);
                }
            }
        } else {
            log.error("同步用户信息失败：{}", JSONUtil.toJsonStr(mhRet));
        }
    }

    private UserAvailableEnum getUserAvailable(Integer status) {
        return status == null || status == 0 ? UserAvailableEnum.DISABLE : UserAvailableEnum.ENABLE;
    }

    public void syncUnits() {
        MhRetDTO<List<MhUnitDTO>> mhRet = mhApiClient.queryUnits();
        if (mhRet.isOk()) {
            List<MhUnitDTO> mhUnits = mhRet.getData();
            if (mhUnits == null || mhUnits.isEmpty()) {
                log.info("未获取到组织信息");
                return;
            }
            List<MhUnit> updateList = new ArrayList<>();
            for (MhUnitDTO org : mhUnits) {
                MhUnit unit = new MhUnit();
                unit.setSort((short) Double.parseDouble(org.getSortNum()));
                unit.setName(org.getUnitName());
                unit.setParentId(org.getUnitPid());
                unit.setId(org.getUnitId());
                updateList.add(unit);
            }
            mhUnitService.saveOrUpdateBatch(updateList);
        } else {
            log.error("同步组织信息失败：{}", JSONUtil.toJsonStr(mhRet));
        }
    }

    public void syncCompany() {
        MhRetDTO<List<MhCompanyDTO>> mhRet = mhApiClient.queryCompany();
        if (mhRet.isOk()) {
            List<MhCompanyDTO> mhUnits = mhRet.getData();
            if (mhUnits == null || mhUnits.isEmpty()) {
                log.info("未获取到组织信息");
                return;
            }
            List<MhCompany> updateList = new ArrayList<>();
            for (MhCompanyDTO org : mhUnits) {
                MhCompany company = new MhCompany();
                company.setCompanyCode(org.getCode());
                company.setCompanyName(org.getCompanyName());
                company.setId(org.getId());
                updateList.add(company);
            }
            mhCompanyService.saveOrUpdateBatch(updateList);
        } else {
            log.error("同步组织信息失败：{}", JSONUtil.toJsonStr(mhRet));
        }
    }

    public void syncExperts(LocalDateTime syncDateTime) {
        MhRetDTO<MhExpertDTO> mhRet = mhApiClient.queryExperts(syncDateTime);
        if (mhRet.isOk()) {
            MhExpertDTO data = mhRet.getData();
            if (data == null) {
                return;
            }
            List<MhReviewExpertDTO> reviewExperts = data.getReviewExpertVOList();
            if (CollUtil.isNotEmpty(reviewExperts)) {
                saveReviewExperts(reviewExperts);
            }
            List<MhTechExpertDTO> techExperts = data.getTechnicalExpertVOList();
            if (CollUtil.isNotEmpty(techExperts)) {
                saveTechExperts(techExperts);
            }
        } else {
            log.error("同步专家信息失败：{}", JSONUtil.toJsonStr(mhRet));
        }
    }

    private void saveReviewExperts(List<MhReviewExpertDTO> reviewExperts) {
        List<String> expertNos = CollUtils.fieldList(reviewExperts, MhReviewExpertDTO::getExpertNo);
        Map<String, ExpertUserFullInfo> expertMap = getExpertsMapMhExpertNo(expertNos);
        for (MhReviewExpertDTO expert : reviewExperts) {
            ExpertUserFullInfo eui = new ExpertUserFullInfo();
            eui.setWechatOpenId(expert.getOpenId());
            eui.setAvatarFile(expert.getFilePhoto());
            BizUtils.notNull(expert.getBirthday(), w -> eui.setBirthday(DateUtil.date(w).toLocalDateTime().toLocalDate()));
            eui.setExpertName(expert.getName());
            eui.setMhExpertNo(expert.getExpertNo());
            eui.setEmail(expert.getEmail());
            eui.setExperience(expert.getExperience());
            eui.setGender(expert.getGender());
            eui.setStar(expert.getStar());
            eui.setSchoolMajor(expert.getSchool());
            LocalDateTime inputTime = DateUtil.parse(expert.getInPutTime()).toLocalDateTime();
            eui.setInPutTime(inputTime);
            eui.setEducation(expert.getEducation());
            eui.setNationality(expert.getNation());
            eui.setHometown(expert.getNativePlace());
            eui.setIsPut(expert.getIsPut());
            eui.setPhoneNo(expert.getPhone());
            eui.setUnit(expert.getUnit());
            eui.setUnitType(expert.getNature());
            eui.setOfficePhone(expert.getTel());
            eui.setAcademicTitle(expert.getTitle());
            eui.setPolitical(expert.getPolitical());
            eui.setDuties(expert.getDuties());
            eui.setAddress(expert.getPlace());
            eui.setUnitAdvice(expert.getUnit());
            eui.setResume(expert.getRemark());
            eui.setMhExpertId(expert.getId());
            ExpertUserFullInfo oldEui = expertMap.get(eui.getMhExpertNo());
            if (oldEui == null) {
                UserInfo expertUser = new UserInfo();
                expertUser.setUsername(expert.getName());
                expertUser.setMobile(expert.getPhone());
                expertUser.setRealName(expert.getName());
                expertUser.setWechatOpenId(expert.getOpenId());
                userInfoService.save(expertUser);
                eui.setUserId(expertUser.getId());
            } else {
                eui.setUserId(oldEui.getUserId());
                eui.setId(oldEui.getId());
            }
            expertUserFullInfoService.saveOrUpdate(eui);
            String expertLevel = expert.getExpertLevel();
            List<ExpertDictionary> dicts = new ArrayList<>();
            Optional<DictionaryDTO> typeDict = dictionaryCache.getByCode("300000");
            typeDict.ifPresent(dict -> dicts.add(getExpertDictionary(eui.getUserId(), dict)));

            Optional<DictionaryDTO> levelDict = dictionaryCache.getByDictTypeAndName(EXPERT_LEVEL.getKey(), expertLevel);
            levelDict.ifPresent(dict -> dicts.add(getExpertDictionary(eui.getUserId(), dict)));

            String grade = expert.getGrade();
            Optional<DictionaryDTO> gradeDict = dictionaryCache.getByDictTypeAndName(EXPERT_LIBRARY.getKey(), grade);
            gradeDict.ifPresent(dict -> dicts.add(getExpertDictionary(eui.getUserId(), dict)));

            String area = expert.getArea();
            Optional<DictionaryDTO> areaDict = dictionaryCache.getByDictTypeAndName(EXPERT_AREA.getKey(), area);
            areaDict.ifPresent(dict -> dicts.add(getExpertDictionary(eui.getUserId(), dict)));

            String skills = expert.getSkills();
            if (StrUtil.isNotBlank(skills)) {
                List<ExpertDictionary> skillsDicts = getSkillsDicts(skills, eui.getUserId());
                if (!skillsDicts.isEmpty()) {
                    dicts.addAll(skillsDicts);
                }
            }
            expertDictionaryService.removeByUserId(eui.getUserId());
            expertDictionaryService.saveBatch(dicts);
        }

    }

    private void saveTechExperts(List<MhTechExpertDTO> techExperts) {
        List<String> expertNos = CollUtils.fieldList(techExperts, MhTechExpertDTO::getExpertNo);
        Map<String, ExpertUserFullInfo> expertMap = getExpertsMapMhExpertNo(expertNos);
        for (MhTechExpertDTO expert : techExperts) {
            ExpertUserFullInfo eui = new ExpertUserFullInfo();
            eui.setWechatOpenId(expert.getOpenId());
            eui.setAvatarFile(expert.getFilePhoto());
            BizUtils.notNull(expert.getBirthday(), w -> eui.setBirthday(DateUtil.date(w).toLocalDateTime().toLocalDate()));
            eui.setExpertName(expert.getName());
            eui.setMhExpertNo(expert.getExpertNo());
            eui.setExperience(expert.getTextExperience());
            eui.setResume(expert.getTextNotes());
            eui.setGender(expert.getGender());
            eui.setStar(expert.getStar());
            eui.setIdCard(expert.getIdCard());
            eui.setIdCardFile(expert.getFileIdCard());
            eui.setRecommendFile(expert.getFileRecommend());
            eui.setSocialInsureFile(expert.getFileSocial());
            eui.setGraduationCertFile(expert.getFileDiploma());
            eui.setDegreeCertFile(expert.getFileDegree());
            eui.setMhCreateOn(LocalDateTimeUtil.of(expert.getCreateTime()));
            eui.setMhCreateBy(expert.getCreateUser());
            LocalDateTime inputTime = DateUtil.parse(expert.getInPutTime()).toLocalDateTime();
            eui.setInPutTime(inputTime);
            eui.setEducation(expert.getEducation());
            eui.setIsPut(expert.getIsPut());
            eui.setPhoneNo(expert.getPhone());
            eui.setMhCompanyId(expert.getCompanyId());
            eui.setPolitical(expert.getPolitical());
            eui.setItaicCredentials(expert.getCredentialsSpeciality());
            eui.setMajorCredentials(expert.getCredentialsTechnology());
            eui.setOtherFile(expert.getFileOther());
            eui.setMhExpertId(expert.getId());
            BizUtils.notBlank(expert.getCartDate(), w -> {
                LocalDateTime certDate = DateUtil.parseDate(w).toLocalDateTime();
                eui.setAwardCertDate(certDate);
            });
            ExpertUserFullInfo oldEui = expertMap.get(eui.getMhExpertNo());
            if (oldEui == null) {
                UserInfo expertUser = new UserInfo();
                expertUser.setUsername(expert.getName());
                expertUser.setMobile(expert.getPhone());
                expertUser.setRealName(expert.getName());
                expertUser.setWechatOpenId(expert.getOpenId());
                userInfoService.save(expertUser);
                eui.setUserId(expertUser.getId());
            } else {
                eui.setUserId(oldEui.getUserId());
                eui.setId(oldEui.getId());
            }
            expertUserFullInfoService.saveOrUpdate(eui);
            List<ExpertDictionary> dicts = new ArrayList<>();
            Optional<DictionaryDTO> typeDict = dictionaryCache.getByCode("300001");
            typeDict.ifPresent(dict -> dicts.add(getExpertDictionary(eui.getUserId(), dict)));
            // 专家级别
            String expertLevel = expert.getExpertLevel();
            Optional<DictionaryDTO> levelDict = dictionaryCache.getByDictTypeAndName(EXPERT_LEVEL.getKey(), expertLevel);
            levelDict.ifPresent(dict -> dicts.add(getExpertDictionary(eui.getUserId(), dict)));
            // 专家来源
            String expertCate = expert.getExpertCate();
            Optional<DictionaryDTO> sourceDict = dictionaryCache.getByDictTypeAndName(EXPERT_SOURCE.getKey(), expertCate);
            sourceDict.ifPresent(dict -> dicts.add(getExpertDictionary(eui.getUserId(), dict)));

            String skills = expert.getSkills();
            if (StrUtil.isNotBlank(skills)) {
                List<ExpertDictionary> skillsDicts = getSkillsDicts(skills, eui.getUserId());
                if (!skillsDicts.isEmpty()) {
                    dicts.addAll(skillsDicts);
                }
            }
            expertDictionaryService.removeByUserId(eui.getUserId());
            expertDictionaryService.saveBatch(dicts);
        }

    }

    private List<ExpertDictionary> getSkillsDicts(String skills, Long userId) {
        List<ExpertDictionary> dicts = new ArrayList<>();
        List<DictionaryDTO> skillsDict = dictionaryCache.listDictByDictType(EXPERT_SPECIALTY.getKey());
        if (StrUtil.isNotBlank(skills)) {
            for (String skill : CollUtil.newHashSet(skills.split("[,、，]"))) {
                Optional<DictionaryDTO> first = skillsDict.stream()
                        .filter(dict -> dict.getName().equals(skill.trim()))
                        .findFirst();
                first.ifPresent(dict -> dicts.add(getExpertDictionary(userId, dict)));
            }
        }
        return dicts;
    }

    private ExpertDictionary getExpertDictionary(Long userId, DictionaryDTO dict) {
        ExpertDictionary dictionary = new ExpertDictionary();
        dictionary.setUserId(userId);
        dictionary.setDictionaryCode(dict.getDictionaryCode());
        dictionary.setExpertInfoField(dict.getDictionaryType());
        return dictionary;
    }

    private Map<String, ExpertUserFullInfo> getExpertsMapMhExpertNo(List<String> expertNos) {
        LambdaQueryWrapper<ExpertUserFullInfo> euiQuery = Wrappers.lambdaQuery(ExpertUserFullInfo.class)
                .select(ExpertUserFullInfo::getMhExpertNo, ExpertUserFullInfo::getUserId, ExpertUserFullInfo::getId)
                .in(ExpertUserFullInfo::getMhExpertNo, expertNos);
        List<ExpertUserFullInfo> experts = expertUserFullInfoService.list(euiQuery);
        return CollUtils.listToMap(experts, ExpertUserFullInfo::getMhExpertNo);
    }

}
