package org.qinan.safetyeval.infrastructure.gatewayimpl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jjb.saas.framework.enums.enums.BooleanEnum;
import com.jjb.saas.system.client.user.request.FacadeUserUpdateStatusEnumBatchCmd;
import com.jjb.saas.system.client.user.request.UserUpdatePasswordCmd;
import com.jjb.saas.system.client.user.request.UserUpdateQuitCmd;
import com.zcloud.gbscommon.utils.MD5;
import com.zcloud.gbscommon.utils.Sm2Util;
import lombok.extern.slf4j.Slf4j;
import org.qinan.safetyeval.domain.entity.OrgInfoEntity;
import org.qinan.safetyeval.domain.exception.BizException;
import org.qinan.safetyeval.domain.exception.ErrorCode;
import org.qinan.safetyeval.domain.gateway.OrgInfoGateway;
import org.qinan.safetyeval.domain.query.OrgInfoQuery;
import org.qinan.safetyeval.domain.query.PageResult;
import org.qinan.safetyeval.infrastructure.adapter.auth.AuthUserContextAdapter;
import org.qinan.safetyeval.infrastructure.adapter.gbs.GbsUserFacadeClient;
import org.qinan.safetyeval.infrastructure.dataobject.OrgInfoDO;
import org.qinan.safetyeval.infrastructure.dataobject.OrgPersonnelDO;
import org.qinan.safetyeval.infrastructure.mapper.OrgInfoMapper;
import org.qinan.safetyeval.infrastructure.mapper.OrgPersonnelMapper;
import org.qinan.safetyeval.infrastructure.support.InsertFieldDefaults;
import org.qinan.safetyeval.infrastructure.support.OrgInfoCascadeDeleter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 机构信息Gateway实现（Infrastructure层）
 *
 * @author safety-eval
 */
@Component
@Slf4j
public class OrgInfoGatewayImpl implements OrgInfoGateway {

    private static final Logger LOGGER = LoggerFactory.getLogger(OrgInfoGatewayImpl.class);

    @Resource
    private OrgInfoMapper orgInfoMapper;
    @Resource
    private OrgPersonnelMapper orgPersonnelMapper;
    @Resource
    private OrgInfoCascadeDeleter orgInfoCascadeDeleter;
    @Autowired
    private GbsUserFacadeClient gbsUserFacadeClient;
    @Value("${def.password:a123456}")
    private String defPassword;
    @Value("${def.publicKey:0402df2195296d4062ac85ad766994d73e871b887e18efb9a9a06b4cebc72372869b7da6c347c129dee2b46a0f279ff066b01c76208c2a052af75977c722a2ccee}")
    private String publicKey;


    @Value("${safety-eval.gbs-user-sync.fail-fast:true}")
    private boolean gbsUserSyncFailFast;

    @Override
    public OrgInfoEntity save(OrgInfoEntity entity) {
        OrgInfoDO dataObject = toDO(entity);
        if (dataObject.getState() == null) {
            dataObject.setState(0);
        }
        InsertFieldDefaults.apply(dataObject);
        orgInfoMapper.insert(dataObject);
        entity.setId(dataObject.getId());
        return entity;
    }

    @Override
    public OrgInfoEntity get(Long id) {
        OrgInfoDO dataObject = orgInfoMapper.selectById(id);
        return toEntity(dataObject);
    }

    @Override
    public OrgInfoEntity getByCreditCode(String creditCode) {
        LambdaQueryWrapper<OrgInfoDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrgInfoDO::getCreditCode, creditCode);
        wrapper.eq(OrgInfoDO::getDeleteEnum, "false");
        OrgInfoDO dataObject = orgInfoMapper.selectOne(wrapper);
        return toEntity(dataObject);
    }

    @Override
    public OrgInfoEntity modify(OrgInfoEntity entity) {
        OrgInfoDO dataObject = toDO(entity);
        dataObject.setId(entity.getId());
        InsertFieldDefaults.applyForUpdate(dataObject);
        orgInfoMapper.updateById(dataObject);
        return get(entity.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        // 同步删除gbs用户(gbs物理)
        List<Long> departUserId = orgInfoMapper.selectList(new LambdaQueryWrapper<OrgInfoDO>()
                        .select(OrgInfoDO::getCreateId)
                        .eq(OrgInfoDO::getId, id)).stream()
                .map(OrgInfoDO::getCreateId).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(departUserId)){
            throw new BizException(ErrorCode.ORG_DEPARTMENT_NOT_FOUND);
        }
        gbsUserFacadeClient.delete(departUserId.get(0));
        List<Long> orgPersonnelDOIdS = orgPersonnelMapper.selectList(new LambdaQueryWrapper<OrgPersonnelDO>()
                .eq(OrgPersonnelDO::getOrgId, id)).stream().map(OrgPersonnelDO::getId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(orgPersonnelDOIdS)) {
            for (Long orgPersonnelDOId : orgPersonnelDOIdS) {
                gbsUserFacadeClient.delete(orgPersonnelDOId);
            }
        }
        orgInfoCascadeDeleter.deleteRelatedData(id);
        orgInfoMapper.deleteById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateState(Long id, Integer state) {
        OrgInfoDO update = new OrgInfoDO();
        update.setId(id);
        update.setState(state);
        InsertFieldDefaults.applyForUpdate(update);
        orgInfoMapper.updateById(update);
        List<Long> departUserId = orgInfoMapper.selectList(new LambdaQueryWrapper<OrgInfoDO>()
                        .select(OrgInfoDO::getCreateId)
                        .eq(OrgInfoDO::getId, id)).stream()
                .map(OrgInfoDO::getCreateId).collect(Collectors.toList());

        boolean enabled = state == 1;
        FacadeUserUpdateStatusEnumBatchCmd cmd = new FacadeUserUpdateStatusEnumBatchCmd();
        cmd.setIds(departUserId);
        cmd.setStatusEnum(enabled ? BooleanEnum.FALSE.getValue() : BooleanEnum.TRUE.getValue());
        gbsUserFacadeClient.updateStatusEnumBatch(cmd);

        // 同步启用禁用gbs用户
        List<Long> userIdList = orgPersonnelMapper.selectList(new LambdaQueryWrapper<OrgPersonnelDO>()
                .select(OrgPersonnelDO::getId)
                .eq(OrgPersonnelDO::getOrgId, id)).stream().map(OrgPersonnelDO::getId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(userIdList)) {
            log.info("部门下面没有用户，不用启用禁用数据");
            return;
        }
        for (Long orgPersonnelDOId : userIdList) {
            UserUpdateQuitCmd userUpdateQuitCmd = new UserUpdateQuitCmd();
            userUpdateQuitCmd.setId(orgPersonnelDOId);
            if (enabled) {
                // 禁用
                gbsUserFacadeClient.quit(userUpdateQuitCmd);
            } else {
                // 启用
                gbsUserFacadeClient.restoreJob(userUpdateQuitCmd);
            }
        }


    }

    @Override
    public PageResult<OrgInfoEntity> page(OrgInfoQuery query) {
        LambdaQueryWrapper<OrgInfoDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrgInfoDO::getDeleteEnum, "false");
        if (StringUtils.hasText(query.getUnitName())) {
            wrapper.like(OrgInfoDO::getUnitName, query.getUnitName());
        }
        if (query.getCreditCode() != null) {
            wrapper.eq(OrgInfoDO::getCreditCode, query.getCreditCode());
        }
        if (query.getAuthStatusCode() != null) {
            wrapper.eq(OrgInfoDO::getAuthStatusCode, query.getAuthStatusCode());
        }
        if (query.getTenantId() != null) {
            wrapper.eq(OrgInfoDO::getTenantId, query.getTenantId());
        }
        if (StringUtils.hasText(query.getDistrictName())) {
            wrapper.eq(OrgInfoDO::getDistrictName, query.getDistrictName());
        }
        if (query.getState() != null) {
            wrapper.eq(OrgInfoDO::getState, query.getState());
        }
        if (query.getCreateTimeStart() != null) {
            wrapper.ge(OrgInfoDO::getCreateTime, query.getCreateTimeStart().atStartOfDay());
        }
        if (query.getCreateTimeEnd() != null) {
            wrapper.lt(OrgInfoDO::getCreateTime, query.getCreateTimeEnd().plusDays(1).atStartOfDay());
        }
        if (StringUtils.hasText(query.getRegisterAddress())) {
            wrapper.like(OrgInfoDO::getRegisterAddress, query.getRegisterAddress());
        }
        if (StringUtils.hasText(query.getFilingTypeCode())) {
            wrapper.eq(OrgInfoDO::getFilingTypeCode, query.getFilingTypeCode());
        }
        if (query.getFilingRecordStatusCode() != null) {
            wrapper.eq(OrgInfoDO::getFilingRecordStatusCode, query.getFilingRecordStatusCode());
        }

        Page<OrgInfoDO> page = new Page<>(query.getPageNum(), query.getPageSize());
        IPage<OrgInfoDO> result = orgInfoMapper.selectPage(page, wrapper);

        List<OrgInfoEntity> entities = result.getRecords().stream()
                .map(this::toEntity)
                .collect(Collectors.toList());

        return PageResult.of(entities, result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    public OrgInfoEntity getInfo() {
        // 查询人员有无机构信息
        Long currentUserId = AuthUserContextAdapter.getCurrentUserId();
        OrgPersonnelDO orgPersonnelDO = orgPersonnelMapper.selectById(currentUserId);
        LambdaQueryWrapper<OrgInfoDO> lqw = new LambdaQueryWrapper<OrgInfoDO>()
                .eq(OrgInfoDO::getCreateId, currentUserId);
        if (orgPersonnelDO != null && orgPersonnelDO.getOrgId() != null) {
            lqw.or().eq(OrgInfoDO::getId, orgPersonnelDO.getOrgId());
        }
        lqw.last("limit 1").orderByDesc(OrgInfoDO::getId);
        List<OrgInfoDO> dataObject = orgInfoMapper.selectList(lqw);
        if (dataObject.isEmpty()) {
            return null;
        }
        return toEntity(dataObject.get(0));
    }

    @Override
    public void resetPassword(Long id) {
        // 同步重置gbs用户密码
        UserUpdatePasswordCmd userUpdatePasswordCmd = new UserUpdatePasswordCmd();
        userUpdatePasswordCmd.setId(id);
        String encrypt = Sm2Util.encryptHex(MD5.md5(defPassword), publicKey);
        userUpdatePasswordCmd.setPassword(encrypt);
        syncGbsUser("reset user password", new Runnable() {
            @Override
            public void run() {
                gbsUserFacadeClient.updatePassword(userUpdatePasswordCmd);
            }
        });
    }

    private void syncGbsUser(String action, Runnable runnable) {
        try {
            runnable.run();
        } catch (RuntimeException ex) {
            LOGGER.warn("GBS user sync failed while {}", action, ex);
            if (gbsUserSyncFailFast) {
                throw ex;
            }
        }
    }

    private OrgInfoDO toDO(OrgInfoEntity entity) {
        OrgInfoDO dataObject = new OrgInfoDO();
        dataObject.setUnitName(entity.getUnitName());
        dataObject.setCreditCode(entity.getCreditCode());
        dataObject.setSafetyIndustryCategoryCode(entity.getSafetyIndustryCategoryCode());
        dataObject.setSafetyIndustryCategoryName(entity.getSafetyIndustryCategoryName());
        dataObject.setDistrictCode(entity.getDistrictCode());
        dataObject.setDistrictName(entity.getDistrictName());
        dataObject.setTownStreet(entity.getTownStreet());
        dataObject.setVillageCommunity(entity.getVillageCommunity());
        dataObject.setLongitude(entity.getLongitude());
        dataObject.setLatitude(entity.getLatitude());
        dataObject.setRegisterAddress(entity.getRegisterAddress());
        dataObject.setBusinessAddress(entity.getBusinessAddress());
        dataObject.setOwnershipTypeCode(entity.getOwnershipTypeCode());
        dataObject.setOwnershipTypeName(entity.getOwnershipTypeName());
        dataObject.setLegalRepresentative(entity.getLegalRepresentative());
        dataObject.setLegalRepresentativePhone(entity.getLegalRepresentativePhone());
        dataObject.setPrincipalName(entity.getPrincipalName());
        dataObject.setPrincipalPhone(entity.getPrincipalPhone());
        dataObject.setSafetyDeptManager(entity.getSafetyDeptManager());
        dataObject.setSafetyDeptManagerPhone(entity.getSafetyDeptManagerPhone());
        dataObject.setSafetyDeputyPhone(entity.getSafetyDeputyPhone());
        dataObject.setProductionDate(entity.getProductionDate());
        dataObject.setBusinessStatusCode(entity.getBusinessStatusCode());
        dataObject.setBusinessStatusName(entity.getBusinessStatusName());
        dataObject.setInfoDisclosureUrl(entity.getInfoDisclosureUrl());
        dataObject.setWorkplaceArea(entity.getWorkplaceArea());
        dataObject.setArchiveRoomArea(entity.getArchiveRoomArea());
        dataObject.setFulltimeEvaluatorCount(entity.getFulltimeEvaluatorCount());
        dataObject.setRegisteredEngineerCount(entity.getRegisteredEngineerCount());
        dataObject.setEconomyIndustryCode(entity.getEconomyIndustryCode());
        dataObject.setEconomyIndustryName(entity.getEconomyIndustryName());
        dataObject.setAuthStatusCode(entity.getAuthStatusCode());
        dataObject.setAuthStatusName(entity.getAuthStatusName());
        dataObject.setEnterpriseStatusCode(entity.getEnterpriseStatusCode());
        dataObject.setEnterpriseStatusName(entity.getEnterpriseStatusName());
        dataObject.setEnterpriseScaleCode(entity.getEnterpriseScaleCode());
        dataObject.setEnterpriseScaleName(entity.getEnterpriseScaleName());
        dataObject.setFilingTypeCode(entity.getFilingTypeCode());
        dataObject.setFilingTypeName(entity.getFilingTypeName());
        dataObject.setFilingRecordStatusCode(entity.getFilingRecordStatusCode());
        dataObject.setFilingRecordStatusName(entity.getFilingRecordStatusName());
        dataObject.setAttachmentUrls(entity.getAttachmentUrls());
        dataObject.setState(entity.getState());
        dataObject.setTenantId(entity.getTenantId());
        return dataObject;
    }

    private OrgInfoEntity toEntity(OrgInfoDO dataObject) {
        if (dataObject == null) {
            return null;
        }
        OrgInfoEntity entity = new OrgInfoEntity();
        entity.setId(dataObject.getId());
        entity.setUnitName(dataObject.getUnitName());
        entity.setCreditCode(dataObject.getCreditCode());
        entity.setSafetyIndustryCategoryCode(dataObject.getSafetyIndustryCategoryCode());
        entity.setSafetyIndustryCategoryName(dataObject.getSafetyIndustryCategoryName());
        entity.setDistrictCode(dataObject.getDistrictCode());
        entity.setDistrictName(dataObject.getDistrictName());
        entity.setTownStreet(dataObject.getTownStreet());
        entity.setVillageCommunity(dataObject.getVillageCommunity());
        entity.setLongitude(dataObject.getLongitude());
        entity.setLatitude(dataObject.getLatitude());
        entity.setRegisterAddress(dataObject.getRegisterAddress());
        entity.setBusinessAddress(dataObject.getBusinessAddress());
        entity.setOwnershipTypeCode(dataObject.getOwnershipTypeCode());
        entity.setOwnershipTypeName(dataObject.getOwnershipTypeName());
        entity.setLegalRepresentative(dataObject.getLegalRepresentative());
        entity.setLegalRepresentativePhone(dataObject.getLegalRepresentativePhone());
        entity.setPrincipalName(dataObject.getPrincipalName());
        entity.setPrincipalPhone(dataObject.getPrincipalPhone());
        entity.setSafetyDeptManager(dataObject.getSafetyDeptManager());
        entity.setSafetyDeptManagerPhone(dataObject.getSafetyDeptManagerPhone());
        entity.setSafetyDeputyPhone(dataObject.getSafetyDeputyPhone());
        entity.setProductionDate(dataObject.getProductionDate());
        entity.setBusinessStatusCode(dataObject.getBusinessStatusCode());
        entity.setBusinessStatusName(dataObject.getBusinessStatusName());
        entity.setInfoDisclosureUrl(dataObject.getInfoDisclosureUrl());
        entity.setWorkplaceArea(dataObject.getWorkplaceArea());
        entity.setArchiveRoomArea(dataObject.getArchiveRoomArea());
        entity.setFulltimeEvaluatorCount(dataObject.getFulltimeEvaluatorCount());
        entity.setRegisteredEngineerCount(dataObject.getRegisteredEngineerCount());
        entity.setEconomyIndustryCode(dataObject.getEconomyIndustryCode());
        entity.setEconomyIndustryName(dataObject.getEconomyIndustryName());
        entity.setAuthStatusCode(dataObject.getAuthStatusCode());
        entity.setAuthStatusName(dataObject.getAuthStatusName());
        entity.setEnterpriseStatusCode(dataObject.getEnterpriseStatusCode());
        entity.setEnterpriseStatusName(dataObject.getEnterpriseStatusName());
        entity.setEnterpriseScaleCode(dataObject.getEnterpriseScaleCode());
        entity.setEnterpriseScaleName(dataObject.getEnterpriseScaleName());
        entity.setFilingTypeCode(dataObject.getFilingTypeCode());
        entity.setFilingTypeName(dataObject.getFilingTypeName());
        entity.setFilingRecordStatusCode(dataObject.getFilingRecordStatusCode());
        entity.setFilingRecordStatusName(dataObject.getFilingRecordStatusName());
        entity.setAttachmentUrls(dataObject.getAttachmentUrls());
        entity.setState(dataObject.getState());
        entity.setTenantId(dataObject.getTenantId());
        entity.setCreateTime(dataObject.getCreateTime());
        return entity;
    }
}
