package com.bocloud.ims.service.transportor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.common.LocationDriver;
import com.bocloud.cmp.entity.enums.ModuleCode;
import com.bocloud.cmp.entity.enums.ResourceCategory;
import com.bocloud.cmp.model.*;
import com.bocloud.cmp.model.azure.AvailabilitySetModel;
import com.bocloud.cmp.model.azure.PublicIPAddressModel;
import com.bocloud.cmp.model.azure.account.BatchAccountModel;
import com.bocloud.cmp.model.azure.account.StorageAccountModel;
import com.bocloud.cmp.model.azure.blob.BlobModel;
import com.bocloud.cmp.model.azure.blob.ContainerModel;
import com.bocloud.cmp.model.azure.db.*;
import com.bocloud.cmp.model.azure.ddos.DdosCustomPolicieModel;
import com.bocloud.cmp.model.azure.ddos.DdosProtectionPlanModel;
import com.bocloud.cmp.model.azure.monitor.MetricAlertModel;
import com.bocloud.cmp.model.azure.monitor.MetricCriteriaModel;
import com.bocloud.cmp.model.azure.network.NicIpConfigurationModel;
import com.bocloud.cmp.model.azure.network.RouterTableModel;
import com.bocloud.cmp.model.azure.redis.RedisFirewallRuleModel;
import com.bocloud.cmp.model.azure.redis.RedisModel;
import com.bocloud.cmp.model.azure.slb.*;
import com.bocloud.cmp.model.azure.sync.AzureSyncModel;
import com.bocloud.common.enums.ResourceCatalog;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.common.enums.AzureIpRelationType;
import com.bocloud.ims.common.enums.AzureTaskStatus;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.entity.resource.azure.AvailabilitySet;
import com.bocloud.ims.entity.resource.azure.account.BatchAccount;
import com.bocloud.ims.entity.resource.azure.account.StorageAccount;
import com.bocloud.ims.entity.resource.azure.blob.Blob;
import com.bocloud.ims.entity.resource.azure.blob.Container;
import com.bocloud.ims.entity.resource.azure.db.*;
import com.bocloud.ims.entity.resource.azure.ddos.DdosCustomPolicie;
import com.bocloud.ims.entity.resource.azure.ddos.DdosProtectionPlan;
import com.bocloud.ims.entity.resource.azure.monitor.MetricAlert;
import com.bocloud.ims.entity.resource.azure.monitor.MetricAlertResourceRelation;
import com.bocloud.ims.entity.resource.azure.monitor.MetricCriteria;
import com.bocloud.ims.entity.resource.azure.network.NicIpConfiguration;
import com.bocloud.ims.entity.resource.azure.network.PublicIPAddress;
import com.bocloud.ims.entity.resource.azure.network.ResourcePublicIPAddressRelation;
import com.bocloud.ims.entity.resource.azure.network.RouterTable;
import com.bocloud.ims.entity.resource.azure.redis.CloudRedis;
import com.bocloud.ims.entity.resource.azure.redis.CloudRedisFirewallRule;
import com.bocloud.ims.entity.resource.azure.slb.*;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.repository.resource.azure.AvailabilitySetRepository;
import com.bocloud.ims.repository.resource.azure.account.BatchAccountRepository;
import com.bocloud.ims.repository.resource.azure.account.StorageAccountRepository;
import com.bocloud.ims.repository.resource.azure.blob.BlobRepository;
import com.bocloud.ims.repository.resource.azure.blob.ContainerRepository;
import com.bocloud.ims.repository.resource.azure.db.*;
import com.bocloud.ims.repository.resource.azure.ddos.DdosCustomPolicieRepository;
import com.bocloud.ims.repository.resource.azure.ddos.DdosProtectionPlanRepository;
import com.bocloud.ims.repository.resource.azure.monitor.MetricAlertRepository;
import com.bocloud.ims.repository.resource.azure.monitor.MetricAlertResourceRelationRepository;
import com.bocloud.ims.repository.resource.azure.monitor.MetricCriteriaRepository;
import com.bocloud.ims.repository.resource.azure.network.NicIpConfigurationRepository;
import com.bocloud.ims.repository.resource.azure.network.PublicIPAddressRepository;
import com.bocloud.ims.repository.resource.azure.network.ResourcePublicIPAddressRelationRepository;
import com.bocloud.ims.repository.resource.azure.network.RouterTableRepository;
import com.bocloud.ims.repository.resource.azure.redis.CloudRedisFirewallRuleRepository;
import com.bocloud.ims.repository.resource.azure.redis.CloudRedisRepository;
import com.bocloud.ims.repository.resource.azure.slb.*;
import com.bocloud.ims.service.model.cmdb.CmdbInfo;
import com.bocloud.ims.service.model.cmdb.CmdbRelation;
import com.bocloud.ims.service.utils.ListUtils;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @Company: 博云 www.bocloud.com
 * @ClassName: AzureTransportor
 * @Description:
 * @author: zhenpingLi/李振平
 * @date: 2019/8/7 10:19
 */
@Component("azureTransportor")
public class AzureTransportor implements Transportor {
    private static Logger logger = LoggerFactory.getLogger(AzureTransportor.class);

    @Autowired
    private ImageRepository imageRepository;
    @Autowired
    private FlavorRepository flavorRepository;
    @Autowired
    private VolumeRepository volumeRepository;
    @Autowired
    private SnapshotRepository snapshotRepository;
    @Autowired
    private SecurityGroupRepository securityGroupRepository;
    @Autowired
    private SecurityGroupRuleRepository securityGroupRuleRepository;
    @Autowired
    private ServerSgroupRepository serverSgroupRepository;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private VpcRepository vpcRepository;
    @Autowired
    private SubnetRepository subnetRepository;
    @Autowired
    private ResourceGroupRepository azureResourceGroupRepository;
    @Autowired
    private NetworkInterfaceRepository networkInterfaceRepository;
    @Autowired
    private PoolGroupRepository poolGroupRepository;
    @Autowired
    private ZoneRepository zoneRepository;
    @Autowired
    private BatchAccountRepository batchAccountRepository;
    @Autowired
    private StorageAccountRepository storageAccountRepository;
    @Autowired
    private AvailabilitySetRepository availabilitySetRepository;
    @Autowired
    private PublicIPAddressRepository publicIPAddressRepository;
    @Autowired
    private BackEndRepository backEndRepository;
    @Autowired
    private FrontEndRepository frontEndRepository;
    @Autowired
    private ProbeRepository probeRepository;
    @Autowired
    private LbRuleRepository lbRuleRepository;
    @Autowired
    private InboundNatPoolRepository inboundNatPoolRepository;
    @Autowired
    private InboundNatRuleRepository inboundNatRuleRepository;
    @Autowired
    private SlbRepository slbRepository;
    @Autowired
    private PerformanceTierRepository performanceTierRepository;
    @Autowired
    private ServiceLevelObjectiveRepository serviceLevelObjectiveRepository;
    @Autowired
    private CloudDatabaseServerRepository cloudDatabaseServerRepository;
    @Autowired
    private KeypairRepository keypairRepository;
    @Autowired
    private ServerKeypairRepository serverKeyPairRepository;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private LocationDriver locationDriver;
    @Autowired
    private RouterTableRepository routerTableRepository;
    @Autowired
    private RouterRepository routerRepository;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private BackEndVirtualMachineRepository backEndVirtualMachineRepository;
    @Autowired
    private ResourcePublicIPAddressRelationRepository resourcePublicIPAddressRelationRepository;
    @Autowired
    private MetricAlertRepository metricAlertRepository;
    @Autowired
    private MetricCriteriaRepository metricCriteriaRepository;
    @Autowired
    private DbFirewallRuleRepository dbFirewallRuleRepository;
    @Autowired
    private ContainerRepository containerRepository;
    @Autowired
    private BlobRepository blobRepository;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private CloudDatabaseRepository cloudDatabaseRepository;
    @Autowired
    private CloudDatabaseServerLogRepository cloudDatabaseServerLogRepository;
    @Autowired
    private DbConfigurationRepository dbConfigurationRepository;
    @Autowired
    private CloudRedisRepository cloudRedisRepository;
    @Autowired
    private CloudRedisFirewallRuleRepository cloudRedisFirewallRuleRepository;
    @Autowired
    private DdosProtectionPlanRepository planRepository;
    @Autowired
    private DdosCustomPolicieRepository policieRepository;
    @Autowired
    private MetricAlertResourceRelationRepository metricAlertResourceRelationRepository;
    @Autowired
    private NicIpConfigurationRepository nicIpConfigurationRepository;
    @Autowired
    private DbVnetRuleRepository dbVnetRuleRepository;

    public BocloudResult sync(CloudVendor vendor, Object data, Region region, Long userId, List<CmdbInfo> infos) {
        try {
            if (null != data) {
                if (cloudServerRepository.hasBuilding(vendor.getId())) {
                    return new BocloudResult(false, "该平台下有虚拟机正在创建，请稍后进行同步操作");
                }
                if (cloudRedisRepository.hasBuilding(vendor.getId())) {
                    return new BocloudResult(false, "该平台下有Redis正在创建，请稍后进行同步操作");
                }
                if (cloudDatabaseServerRepository.hasBuilding(vendor.getId())) {
                    return new BocloudResult(false, "该平台下有Mysql正在创建，请稍后进行同步操作");
                }

                String content = JSONObject.toJSONString(data);
                AzureSyncModel model = JSONObject.parseObject(content, AzureSyncModel.class);

                // 同步资源组
                logger.info("starting sync azureResourceGroup......");
                this.syncAzureResourceGroup(model.getResourceGroupModels(), vendor.getId(), userId,
                        region.getRegionId());
                Map<String, ResourceGroup> resourceGroupMap = Optional
                        .ofNullable(azureResourceGroupRepository.listByVendorId(vendor.getId(), region.getRegionId()))
                        .map(groups -> groups.stream().collect(Collectors.toMap(group -> group.getName().toLowerCase(),
                                resourceGroup -> resourceGroup)))
                        .orElse(Maps.newHashMap());
                logger.info("end sync azureResourceGroup !");

                // 同步公共IP地址
                logger.info("starting sync publicIpAddress......");
                this.syncPublicIpAddress(model.getPublicIPAddressModels(), vendor, userId, region.getRegionId(), resourceGroupMap);
                Map<String, PublicIPAddress> publicIPAddressMap = Optional
                        .ofNullable(publicIPAddressRepository.list(vendor.getId(), region.getRegionId()))
                        .map(entitys -> entitys.stream()
                                .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(), entity -> entity)))
                        .orElse(Maps.newHashMap());
                logger.info("end sync publicIpAddress !");

                logger.info("starting sync ddos plan......");
                this.syncDdosProtectionPlan(model.getPlanModels(), vendor, userId, region.getRegionId(), resourceGroupMap);
                logger.info("end sync ddos plan !");

                // 同步规格
                logger.info("starting sync flavor......");
                this.syncFlavor(model.getFlavorModels(), vendor.getId(), region.getRegionId());
                Map<String, Flavor> flavorMap = Optional
                        .ofNullable(flavorRepository.listByVendorId(vendor.getId(), region.getRegionId()))
                        .map(entitys -> entitys.stream().collect(
                                Collectors.toMap(entity -> entity.getFlavorUuid().toLowerCase(), entity -> entity)))
                        .orElse(Maps.newHashMap());
                logger.info("end sync flavor !");

                // 安全组
                logger.info("starting sync security group......");
                this.syncSecurityGroup(model.getSecurityGroupModels(), vendor, userId, region.getRegionId(), resourceGroupMap);
                Map<String, SecurityGroup> groupMap = Optional
                        .ofNullable(securityGroupRepository.listByVendorId(vendor.getId(), region.getRegionId()))
                        .map(entitys -> entitys.stream().collect(
                                Collectors.toMap(entity -> entity.getGroupUuid().toLowerCase(), entity -> entity)))
                        .orElse(Maps.newHashMap());
                logger.info("end sync security group !");

                // 路由表和路由
                logger.info("starting sync router......");
                this.syncRouterTable(model.getRouterTableModels(), vendor, userId, region.getRegionId(), resourceGroupMap);
                logger.info("end sync router  !");
                Map<String, RouterTable> routerMap = Optional.ofNullable(routerTableRepository.listByVendorId(vendor.getId(), region.getRegionId()))
                        .map(entitys -> entitys.stream()
                                .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(), entity -> entity)))
                        .orElse(Maps.newHashMap());
                // vpc和子网
                logger.info("starting sync vpc subnet......");
                this.syncVpc(model.getVpcModels(), vendor.getId(), userId, groupMap, routerMap, region.getRegionId());
                Map<String, Vpc> vpcMap = Optional.ofNullable(vpcRepository.list(vendor.getId(), region.getRegionId()))
                        .map(entitys -> entitys.stream()
                                .collect(Collectors.toMap(entity -> entity.getVpcId().toLowerCase(), entity -> entity)))
                        .orElse(Maps.newHashMap());
                Map<String, Subnet> subnetMap = Optional
                        .ofNullable(subnetRepository.listByRegion(vendor.getId(), region.getRegionId()))
                        .map(entitys -> entitys.stream().collect(
                                Collectors.toMap(entity -> entity.getSubnetUuid().toLowerCase(), entity -> entity)))
                        .orElse(Maps.newHashMap());
                logger.info("end sync vpc subnet !");

                // 同步可用性集
                logger.info("Starting sync availabilitySet......");
                this.syncAvailabilitySet(model.getAvailabilitySetModels(), vendor, userId, region.getRegionId(),
                        resourceGroupMap);
                Map<String, AvailabilitySet> availabilitySetMap = Optional
                        .ofNullable(availabilitySetRepository.list(vendor.getId(), region.getRegionId()))
                        .map(entitys -> entitys.stream()
                                .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(), entity -> entity)))
                        .orElse(Maps.newHashMap());
                logger.info("End sync availabilitySet !");

                // 同步密钥
                logger.info("Starting sync keypair......");
                this.syncKeyPairs(model.getKeypairModels(), vendor.getId(), userId, region.getRegionId(),
                        resourceGroupMap);
                Map<String, Keypair> keypairMap = Optional
                        .ofNullable(keypairRepository.listByVid(vendor.getId(), region.getRegionId()))
                        .map(entitys -> entitys.stream().collect(
                                Collectors.toMap(entity -> entity.getPublicKey().toLowerCase(), entity -> entity)))
                        .orElse(Maps.newHashMap());
                logger.info("End sync keypair !");

                // 因为cloudserver表没有系统盘uuid字段，所以拿取model的所有系统盘
                Map<String, String> systemOsDiskMap = Maps.newHashMap();
                for (ServerModel serverModel : model.getServerModels()) {
                    systemOsDiskMap.put(serverModel.getSystemDiskUuid().toLowerCase(), null);
                }
                // 同步虚拟机
                logger.info("starting sync cloudServer......");
                this.syncServer(model.getServerModels(), vendor, userId, region, infos, groupMap, flavorMap,
                        availabilitySetMap, keypairMap, resourceGroupMap, vpcMap);
                Map<String, CloudServer> serverMap = Optional
                        .ofNullable(cloudServerRepository.listByVendorId(vendor.getId(), region.getRegionId()))
                        .map(entitys -> entitys.stream().collect(
                                Collectors.toMap(entity -> entity.getInstanceId().toLowerCase(), entity -> entity)))
                        .orElse(Maps.newHashMap());
                logger.info("end sync cloudServer !");


                // 同步网络接口 关联安全组 关联vpc 关联虚拟机 关联子网
                logger.info("sync data to networkInterface......");
                this.syncNetworkInterface(model.getNetworkInterfaceModels(), vendor, userId, groupMap, vpcMap,
                        serverMap, subnetMap, region.getRegionId(), publicIPAddressMap, resourceGroupMap);
                logger.info("end sync networkInterface !");

                // 同步云硬盘
                logger.info("starting sync volume......");
                this.syncVolume(model.getVolumeModels(), vendor, userId, serverMap, region.getRegionId(),
                        systemOsDiskMap);
                Map<String, Volume> volumeMap = Optional
                        .ofNullable(volumeRepository.listByVendorId(vendor.getId(), region.getRegionId()))
                        .map(entitys -> entitys.stream().collect(
                                Collectors.toMap(entity -> entity.getVolumeUuid().toLowerCase(), entity -> entity)))
                        .orElse(Maps.newHashMap());
                logger.info("end sync volume !");

                // 同步云快照
                logger.info("starting sync snapshot......");
                this.syncSnapshot(model.getSnapshotModels(), vendor, userId, region.getRegionId(), volumeMap);
                logger.info("end sync snapshot !");

                // 存储账户
                logger.info("starting sync storageAccount......");
                this.syncStorageAccount(model.getStorageAccountModels(), vendor, userId, region.getRegionId(),
                        resourceGroupMap);
                Map<String, StorageAccount> storageAccountMap = Optional
                        .ofNullable(storageAccountRepository.listByVendorId(vendor.getId(), region.getRegionId()))
                        .map(storageAccounts -> storageAccounts.stream()
                                .collect(Collectors.toMap(storageAccount -> storageAccount.getUuid().toLowerCase(),
                                        storageAccount -> storageAccount)))
                        .orElse(Maps.newHashMap());
                logger.info("end sync storageAccount !");

                // Batch账户
                logger.info("starting sync batchAccount......");
                this.syncBatchAccount(model.getBatchAccountModels(), vendor, userId, region.getRegionId(),
                        resourceGroupMap, storageAccountMap);
                logger.info("end sync batchAccount !");

                // 同步负载均衡
                logger.info("starting sync slb......");
                this.syncSlb(model.getSlbModels(), vendor, userId, region.getRegionId(), resourceGroupMap,
                        publicIPAddressMap, serverMap, subnetMap);
                logger.info("end sync slb !");

                // 同步azure-PerformanceTier
                logger.info("starting sync performanceTier......");
                this.syncPerformanceTier(model.getPerformanceTierModels(), vendor, region.getRegionId());
                logger.info("end sync performanceTier !");
                Map<String, ServiceLevelObjective> sloMap = Optional
                        .ofNullable(serviceLevelObjectiveRepository.listByVid(vendor.getId(), region.getRegionId()))
                        .map(entitys -> entitys.stream()
                                .collect(Collectors.toMap(entity -> entity.getUuid() + entity.getRegionId() + entity.getDbType(), entity -> entity)))
                        .orElse(Maps.newHashMap());

                logger.info("starting sync database......");
                this.syncCloudDatabaseServer(model.getAzureDatabaseServerModels(), vendor, userId, region.getRegionId(),
                        resourceGroupMap, sloMap, subnetMap);
                logger.info("end sync database !");

                logger.info("starting sync database bind......");
                Map<String, AzureDatabaseServer> mysqlMap = Optional
                        .ofNullable(cloudDatabaseServerRepository.listByVendorId(vendor.getId()))
                        .map(entitys -> entitys.stream()
                                .collect(Collectors.toMap(entity -> entity.getDatabaseServerUuid().toLowerCase(), entity -> entity)))
                        .orElse(Maps.newHashMap());
                //同步关系
                for (AzureDatabaseServerModel serverModel : model.getAzureDatabaseServerModels()) {
                    AzureDatabaseServer masterServer = mysqlMap.get(serverModel.getDatabaseServerUuid().toLowerCase());
                    if (!ObjectUtils.isEmpty(masterServer)) {
                        //存在 一定是主服务器，不存在不一定是副本服务器
                        if (!CollectionUtils.isEmpty(serverModel.getReplicaUuids())) {
                            for (String replicaUuid : serverModel.getReplicaUuids()) {
                                AzureDatabaseServer replicaServer = mysqlMap.get(replicaUuid.toLowerCase());
                                if (!ObjectUtils.isEmpty(replicaServer)) {
                                    replicaServer.setIsMaster(false);
                                    replicaServer.setMasterServerId(masterServer.getId());
                                    cloudDatabaseServerRepository.update(replicaServer);
                                }
                            }
                        }
                    }
                }
                logger.info("starting sync database bind......");
                logger.info("starting sync redis......");
                this.syncCloudRedis(model.getRedisModels(), vendor, userId, region.getRegionId(),
                        resourceGroupMap, subnetMap);
                logger.info("end sync redis !");

                logger.info("starting sync metricAlert......");
                Map<String, CloudServer> allServerMap = Optional
                        .ofNullable(cloudServerRepository.listByVendorId(vendor.getId()))
                        .map(entitys -> entitys.stream().collect(
                                Collectors.toMap(entity -> entity.getInstanceId().toLowerCase(), entity -> entity)))
                        .orElse(Maps.newHashMap());
                Map<String, CloudRedis> allRedisMap = Optional
                        .ofNullable(cloudRedisRepository.listByVendorId(vendor.getId()))
                        .map(entitys -> entitys.stream().collect(
                                Collectors.toMap(entity -> entity.getRedisUuid().toLowerCase(), entity -> entity)))
                        .orElse(Maps.newHashMap());
                Map<String, AzureDatabaseServer> allMysqlMap = Optional
                        .ofNullable(cloudDatabaseServerRepository.listByVendorId(vendor.getId()))
                        .map(entitys -> entitys.stream().collect(
                                Collectors.toMap(entity -> entity.getDatabaseServerUuid().toLowerCase(), entity -> entity)))
                        .orElse(Maps.newHashMap());

                this.syncMetricAlert(model.getMetricAlertModels(), vendor, userId, resourceGroupMap, allServerMap, allRedisMap, allMysqlMap);
                logger.info("end sync metricAlert !");

                taskExecutor.execute(() -> {
                    logger.info("线程开始同步映像,地区:{}", region.getRegionId());
                    BocloudResult imageResult = locationDriver.syncImages(vendor.getUuid(), region.getRegionId());
                    String path = CloudVendor.class.getSimpleName() + "_image_" + vendor.getId();
                    try (BocloudACLock lock = lockFactory.getACLock(path)) {
                        Assert.isTrue(lock.acquire(1, TimeUnit.HOURS), "请求超时");
                        List<ImageModel> imageModels = new ArrayList<>();
                        if (imageResult.isSuccess()) {
                            String imageContent = JSONObject.toJSONString(imageResult.getData());
                            AzureSyncModel syncModel = JSONObject.parseObject(imageContent, AzureSyncModel.class);
                            imageModels = syncModel.getImageModels();
                        }
                        logger.info("映像集合大小:{}", imageModels.size());
                        this.syncImage(imageModels, vendor, userId, region.getRegionId());
                        logger.info("线程结束同步映像,地区:{}", region.getRegionId());
                        logger.info(vendor.getName() + "线程同步成功！！！");
                        // 发送给云平台统计队列对云平台重新统计
                        JSONObject object = new JSONObject();
                        object.put(Common.VENDORID, vendor.getId());
                        amqpTemplate.convertAndSend("vendor.statistics.queue", object);
                    } catch (Exception e) {
                        logger.error("获取镜像失败：", e);
                    }
                });
                // 同步zone 和 资源池
                this.syncZone(vendor, userId, region);
                this.resetServerIps(vendor, region);
            }
            return new BocloudResult(true, null, "云平台【 " + vendor.getName() + " 】数据同步成功");
        } catch (Exception e) {
            logger.error("AZURE同步数据失败", e);
            return new BocloudResult(false, e.getMessage(), "云平台【 " + vendor.getName() + " 】数据同步失败");
        }
    }

    /**
     * 删除公共IP绑定关系
     *
     * @param resourceId
     * @param type
     * @throws Exception
     */
    private void removePublicAddressRelation(Long resourceId, AzureIpRelationType type) throws Exception {
        List<ResourcePublicIPAddressRelation> resourcePublicIPAddressRelations = resourcePublicIPAddressRelationRepository.listByResourceId(resourceId, type.name());
        for (ResourcePublicIPAddressRelation relation : resourcePublicIPAddressRelations) {
            PublicIPAddress publicIPAddress = publicIPAddressRepository.query(relation.getIpId());
            if (null != publicIPAddress) {
                publicIPAddress.setStatus(AzureTaskStatus.IN_USE.name());
                publicIPAddressRepository.update(publicIPAddress);
            }
        }
        resourcePublicIPAddressRelationRepository.removeByResourceId(resourceId, type.name());
    }

    /**
     * 重置虚拟机ip信息
     *
     * @param vendor
     * @param region
     * @throws Exception
     */
    private void resetServerIps(CloudVendor vendor, Region region) throws Exception {
        List<CloudServer> servers = cloudServerRepository.listByVid(vendor.getId(), region.getRegionId());
        for (CloudServer cloudServer : servers) {
            List<String> privateIps = new ArrayList<>();
            List<String> publicIps = new ArrayList<>();
            List<NetworkInterface> networkInterfaces = networkInterfaceRepository.listByServerId(vendor.getId(), cloudServer.getId());
            networkInterfaces.stream().forEach(networkInterface -> {
                if (!StringUtils.isEmpty(networkInterface.getPrimaryPrivateIPAddress())) {
                    privateIps.add(networkInterface.getPrimaryPrivateIPAddress());
                }
                if (!StringUtils.isEmpty(networkInterface.getPublicIPAddress())) {
                    publicIps.add(networkInterface.getPublicIPAddress());
                }
            });

            if (!CollectionUtils.isEmpty(privateIps)) {
                cloudServer.setPrivateIps(JSONObject.toJSONString(privateIps));
            } else {
                cloudServer.setPrivateIps(null);
            }
            if (!CollectionUtils.isEmpty(publicIps)) {
                cloudServer.setPublicIps(JSONObject.toJSONString(publicIps));
            } else {
                cloudServer.setPublicIps(null);
            }
            cloudServerRepository.update(cloudServer);
        }
    }

    private void syncMetricCriteria(List<MetricCriteriaModel> models, Long metricAlertId) {
        metricCriteriaRepository.removeByMetricAlertId(metricAlertId);
        for (MetricCriteriaModel model : models) {
            MetricCriteria entity = new MetricCriteria();
            BeanUtils.copyProperties(model, entity);
            entity.setMetricAlertId(metricAlertId);
            metricCriteriaRepository.save(entity);
        }
    }

    private void syncMetricAlert(List<MetricAlertModel> models, CloudVendor vendor, Long userId, Map<String, ResourceGroup> resourceGroupMap, Map<String, CloudServer> serverMap, Map<String, CloudRedis> redisMap, Map<String, AzureDatabaseServer> mysqlMap) {
        if (ListTool.isEmpty(models)) {
            metricAlertRepository.removeByVid(vendor.getId(), userId);
            return;
        }
        Map<String, MetricAlert> map = Optional
                .ofNullable(metricAlertRepository.listByVendorId(vendor.getId()))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (MetricAlertModel model : models) {
            MetricAlert entity = new MetricAlert();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
                metricAlertRepository.update(entity);

                //同步警报与警报规则关系
                syncMetricCriteria(model.getMetricCriteriaModels(), entity.getId());
                //同步警报资源关系
                metricAlertResourceRelationRepository.removeByMetricAlertId(entity.getId());
                saveMetricAlertResourceRelation(entity.getId(), model, serverMap, redisMap, mysqlMap);
//                metricAlertVirtualMachineRepository.removeByMetricAlertId(entity.getId());
//                for (String resourceUuid : model.getResourceUuids()) {
//                    CloudServer server = serverMap.get(resourceUuid.toLowerCase());
//                    if (!ObjectUtils.isEmpty(server)) {
//                        metricAlertVirtualMachineRepository.save(new MetricAlertVirtualMachine(entity.getId(), server.getId()));
//                    }
//                }
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setVendorId(vendor.getId());
            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
            entity.setTenantId(0L);
            entity.setProjectId(0L);
            metricAlertRepository.save(entity);

            //同步警报与警报规则关系
            syncMetricCriteria(model.getMetricCriteriaModels(), entity.getId());
            //同步警报资源关系
            metricAlertResourceRelationRepository.removeByMetricAlertId(entity.getId());
            saveMetricAlertResourceRelation(entity.getId(), model, serverMap, redisMap, mysqlMap);
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, MetricAlert> entry : map.entrySet()) {
            metricAlertRepository.remove(entry.getValue().getId(), userId);
        }
    }

    private void saveMetricAlertResourceRelation(Long metricAlertId, MetricAlertModel model, Map<String, CloudServer> serverMap, Map<String, CloudRedis> redisMap, Map<String, AzureDatabaseServer> mysqlMap) {
        for (String resourceUuid : model.getResourceUuids()) {
            switch (model.getTargetResourceType()) {
                case "Microsoft.Compute/virtualMachines":
                    CloudServer server = serverMap.get(resourceUuid.toLowerCase());
                    if (!ObjectUtils.isEmpty(server)) {
                        metricAlertResourceRelationRepository.save(new MetricAlertResourceRelation(metricAlertId, server.getId(), model.getTargetResourceType()));
                    }
                    break;
                case "Microsoft.DBForMySQL/servers":
                    AzureDatabaseServer databaseServer = mysqlMap.get(resourceUuid.toLowerCase());
                    if (!ObjectUtils.isEmpty(databaseServer)) {
                        metricAlertResourceRelationRepository.save(new MetricAlertResourceRelation(metricAlertId, databaseServer.getId(), model.getTargetResourceType()));
                    }
                    break;
                case "Microsoft.Cache/Redis":
                    CloudRedis cloudRedis = redisMap.get(resourceUuid.toLowerCase());
                    if (!ObjectUtils.isEmpty(cloudRedis)) {
                        metricAlertResourceRelationRepository.save(new MetricAlertResourceRelation(metricAlertId, cloudRedis.getId(), model.getTargetResourceType()));
                    }

                    break;
                default:
                    break;
            }
        }
    }

    private void syncRouterTable(List<RouterTableModel> models, CloudVendor vendor, Long userId, String region, Map<String, ResourceGroup> resourceGroupMap) throws Exception {
        if (ListTool.isEmpty(models)) {
            routerTableRepository.removeByVid(vendor.getId(), region, userId);
            return;
        }
        Map<String, RouterTable> map = Optional
                .ofNullable(routerTableRepository.listByVendorId(vendor.getId(), region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (RouterTableModel model : models) {
            RouterTable entity = new RouterTable();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setRegionId(region);
                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
                routerTableRepository.update(entity);
                model.getRouterModels();
                map.remove(model.getUuid().toLowerCase());
                // 同步子网
                this.syncRouter(model.getRouterModels(), vendor.getId(), userId, entity.getId(),
                        region, resourceGroupMap);
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setVendorId(vendor.getId());
            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
            entity.setTenantId(0L);
            entity.setProjectId(0L);
            entity.setRegionId(region);
            routerTableRepository.save(entity);
            map.remove(model.getUuid().toLowerCase());
            // 同步子网
            this.syncRouter(model.getRouterModels(), vendor.getId(), userId, entity.getId(),
                    region, resourceGroupMap);
        }
        for (Map.Entry<String, RouterTable> entry : map.entrySet()) {
            routerTableRepository.remove(entry.getValue().getId(), userId);
        }
    }

    private void syncRouter(List<RouterModel> models, Long vendorId, Long userId, Long routerTableId, String regionId, Map<String, ResourceGroup> resourceGroupMap) {
        if (ListTool.isEmpty(models)) {
            routerRepository.removeByRouterTableId(routerTableId, userId);
            return;
        }
        Map<String, Router> map = Optional
                .ofNullable(routerRepository.listByRouterTableId(vendorId, routerTableId))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getRouterUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (RouterModel model : models) {
            Router entity = new Router();
            if (map.containsKey(model.getRouterUuid().toLowerCase())) {
                entity = map.get(model.getRouterUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setRouterTableId(routerTableId);
                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
                routerRepository.update(entity);
                map.remove(model.getRouterUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setVendorId(vendorId);
            entity.setRegionId(regionId);
            entity.setRouterTableId(routerTableId);
            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
            routerRepository.save(entity);
            map.remove(model.getRouterUuid().toLowerCase());
        }
        for (Map.Entry<String, Router> entry : map.entrySet()) {
            routerRepository.remove(entry.getValue().getId(), userId);
        }
    }

    private void syncKeyPairs(List<KeypairModel> models, Long vendorId, Long userId, String region, Map<String, ResourceGroup> resourceGroupMap) throws Exception {
        if (ListTool.isEmpty(models)) {
            keypairRepository.removeByVid(vendorId, region, userId);
            return;
        }
        Map<String, Keypair> map = Optional
                .ofNullable(keypairRepository.listByVid(vendorId, region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getFingerprint().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (KeypairModel model : models) {
            Keypair keypair = new Keypair();
            if (map.containsKey(model.getFingerprint().toLowerCase())) {
                keypair = map.get(model.getFingerprint().toLowerCase());
                BeanUtils.copyProperties(model, keypair);
                model.setGmtCreate(keypair.getGmtCreate());
                model.setUserUuid(keypair.getUserUuid());
                keypair.setMenderId(userId);
                keypair.setGmtModify(new Date());
                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(keypair::setResourceGroupId);
                keypairRepository.update(keypair);
                map.remove(keypair.getFingerprint().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, keypair);
            keypair.setCreatorId(userId);
            keypair.setGmtCreate(model.getGmtCreate());
            keypair.setVendorId(vendorId);
            keypair.setTenantId(0L);
            keypair.setProjectId(0L);
            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(keypair::setResourceGroupId);
            keypairRepository.save(keypair);
            map.remove(model.getFingerprint().toLowerCase());
        }
        for (Map.Entry<String, Keypair> entry : map.entrySet()) {
            keypairRepository.remove(entry.getValue().getId(), userId);
        }
    }

    private void syncPerformanceTier(List<PerformanceTierModel> models, CloudVendor vendor, String region) {
        if (ListTool.isEmpty(models)) {
            performanceTierRepository.removeByVid(vendor.getId(), region);
            return;
        }

        Map<String, PerformanceTier> map = Optional
                .ofNullable(performanceTierRepository.listByVid(vendor.getId(), region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid() + entity.getRegionId() + entity.getDbType(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());

        for (PerformanceTierModel model : models) {
            PerformanceTier entity = new PerformanceTier();
            if (map.containsKey(model.getUuid() + model.getRegionId() + model.getDbType())) {
                entity = map.get(model.getUuid() + model.getRegionId() + model.getDbType());
                BeanUtils.copyProperties(model, entity);
                entity.setRegionId(region);
                performanceTierRepository.update(entity);
                this.syncServiceLevelObjective(model.getLevelObjectiveModels(), entity);
                map.remove(model.getUuid() + model.getRegionId() + model.getDbType());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setVendorId(vendor.getId());
            entity.setRegionId(region);
            performanceTierRepository.save(entity);
            this.syncServiceLevelObjective(model.getLevelObjectiveModels(), entity);
            map.remove(model.getUuid() + model.getRegionId() + model.getDbType());
        }
        for (Map.Entry<String, PerformanceTier> entry : map.entrySet()) {
            performanceTierRepository.delete(entry.getValue().getId());
        }
    }

    private void syncServiceLevelObjective(List<ServiceLevelObjectiveModel> models, PerformanceTier performanceTier) {
        if (ListTool.isEmpty(models)) {
            serviceLevelObjectiveRepository.removeByPid(performanceTier.getId());
            return;
        }
        List<ServiceLevelObjective> entitys = serviceLevelObjectiveRepository.listByPid(performanceTier.getId());
        Map<String, ServiceLevelObjective> map = entitys.stream().collect(
                Collectors.toMap(entity -> entity.getUuid() + entity.getRegionId() + entity.getDbType(), entity -> entity));
        for (ServiceLevelObjectiveModel model : models) {
            ServiceLevelObjective entity = new ServiceLevelObjective();
            if (map.containsKey(model.getUuid() + model.getRegionId() + model.getDbType())) {
                entity = map.get(model.getUuid() + model.getRegionId() + model.getDbType());
                BeanUtils.copyProperties(model, entity);
                entity.setRegionId(performanceTier.getRegionId());
                entity.setVendorId(performanceTier.getVendorId());
                entity.setPerformanceTierId(performanceTier.getId());
                serviceLevelObjectiveRepository.update(entity);
                map.remove(model.getUuid() + model.getRegionId() + model.getDbType());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setRegionId(performanceTier.getRegionId());
            entity.setVendorId(performanceTier.getVendorId());
            entity.setPerformanceTierId(performanceTier.getId());
            serviceLevelObjectiveRepository.save(entity);
            map.remove(model.getUuid() + model.getRegionId() + model.getDbType());
        }
        for (Map.Entry<String, ServiceLevelObjective> entry : map.entrySet()) {
            serviceLevelObjectiveRepository.delete(entry.getValue().getId());
        }
    }

    private void syncDbFirewallRule(List<DbFirewallRuleModel> models, Long databaseServerId) {
        if (ListTool.isEmpty(models)) {
            dbFirewallRuleRepository.deleteByDbId(databaseServerId);
            return;
        }
        Map<String, DbFirewallRule> map = Optional
                .ofNullable(dbFirewallRuleRepository.listByDbId(databaseServerId))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());

        for (DbFirewallRuleModel model : models) {
            DbFirewallRule entity = new DbFirewallRule();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setDatabaseServerId(databaseServerId);
                dbFirewallRuleRepository.update(entity);
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setDatabaseServerId(databaseServerId);
            dbFirewallRuleRepository.save(entity);
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, DbFirewallRule> entry : map.entrySet()) {
            dbFirewallRuleRepository.delete(entry.getValue().getId());
        }
    }

    private void syncDbVnetRule(List<DbVnetRuleModel> models, Long databaseServerId, Map<String, Subnet> subnetMap) {
        if (ListTool.isEmpty(models)) {
            dbVnetRuleRepository.deleteByDbId(databaseServerId);
            return;
        }
        Map<String, DbVnetRule> map = Optional
                .ofNullable(dbVnetRuleRepository.listByDbId(databaseServerId))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());

        for (DbVnetRuleModel model : models) {
            DbVnetRule entity = new DbVnetRule();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setDatabaseServerId(databaseServerId);
                Optional.ofNullable(subnetMap.get(model.getSubnetUuid().toLowerCase()))
                        .map(subnet -> subnet.getId()).ifPresent(entity::setSubnetId);
                Optional.ofNullable(subnetMap.get(model.getSubnetUuid().toLowerCase()))
                        .map(subnet -> subnet.getVpcId()).ifPresent(entity::setVpcId);
                dbVnetRuleRepository.update(entity);
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setDatabaseServerId(databaseServerId);
            Optional.ofNullable(subnetMap.get(model.getSubnetUuid().toLowerCase()))
                    .map(subnet -> subnet.getId()).ifPresent(entity::setSubnetId);
            Optional.ofNullable(subnetMap.get(model.getSubnetUuid().toLowerCase()))
                    .map(subnet -> subnet.getVpcId()).ifPresent(entity::setVpcId);
            dbVnetRuleRepository.save(entity);
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, DbVnetRule> entry : map.entrySet()) {
            dbVnetRuleRepository.delete(entry.getValue().getId());
        }
    }

    private void syncDbConfiguration(List<DbConfigurationModel> models, Long databaseServerId) {
        if (ListTool.isEmpty(models)) {
            dbConfigurationRepository.deleteByDbId(databaseServerId);
            return;
        }
        Map<String, DbConfiguration> map = Optional
                .ofNullable(dbConfigurationRepository.listByDbId(databaseServerId))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());

        for (DbConfigurationModel model : models) {
            DbConfiguration entity = new DbConfiguration();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setDatabaseServerId(databaseServerId);
                dbConfigurationRepository.update(entity);
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setDatabaseServerId(databaseServerId);
            dbConfigurationRepository.save(entity);
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, DbConfiguration> entry : map.entrySet()) {
            dbConfigurationRepository.delete(entry.getValue().getId());
        }
    }

    private void syncCloudDatabase(List<AzureDatabaseModel> models, Long databaseServerId) {
        if (ListTool.isEmpty(models)) {
            cloudDatabaseRepository.deleteByDbId(databaseServerId);
            return;
        }
        Map<String, AzureDatabase> map = Optional
                .ofNullable(cloudDatabaseRepository.listByDbId(databaseServerId))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());

        for (AzureDatabaseModel model : models) {
            AzureDatabase entity = new AzureDatabase();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setDatabaseServerId(databaseServerId);
                cloudDatabaseRepository.update(entity);
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setDatabaseServerId(databaseServerId);
            cloudDatabaseRepository.save(entity);
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, AzureDatabase> entry : map.entrySet()) {
            cloudDatabaseRepository.delete(entry.getValue().getId());
        }
    }

    private void syncCloudDatabaseServerLog(List<AzureDatabaseServerLogModel> models, Long databaseServerId) {
        if (ListTool.isEmpty(models)) {
            cloudDatabaseServerLogRepository.deleteByDbId(databaseServerId);
            return;
        }
        Map<String, AzureDatabaseServerLog> map = Optional
                .ofNullable(cloudDatabaseServerLogRepository.listByDbId(databaseServerId))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());

        for (AzureDatabaseServerLogModel model : models) {
            AzureDatabaseServerLog entity = new AzureDatabaseServerLog();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setDatabaseServerId(databaseServerId);
                cloudDatabaseServerLogRepository.update(entity);
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setDatabaseServerId(databaseServerId);
            cloudDatabaseServerLogRepository.save(entity);
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, AzureDatabaseServerLog> entry : map.entrySet()) {
            cloudDatabaseServerLogRepository.delete(entry.getValue().getId());
        }
    }

    private void syncCloudRedisFirewallRule(List<RedisFirewallRuleModel> models, Long redisId) {
        if (ListTool.isEmpty(models)) {
            cloudRedisFirewallRuleRepository.deleteByRedisId(redisId);
            return;
        }
        Map<String, CloudRedisFirewallRule> map = Optional
                .ofNullable(cloudRedisFirewallRuleRepository.listByRedisId(redisId))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());

        for (RedisFirewallRuleModel model : models) {
            CloudRedisFirewallRule entity = new CloudRedisFirewallRule();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setRedisId(redisId);
                cloudRedisFirewallRuleRepository.update(entity);
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setRedisId(redisId);
            cloudRedisFirewallRuleRepository.save(entity);
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, CloudRedisFirewallRule> entry : map.entrySet()) {
            cloudRedisFirewallRuleRepository.delete(entry.getValue().getId());
        }
    }

    private void syncCloudRedis(List<RedisModel> models, CloudVendor vendor, Long userId, String region, Map<String, ResourceGroup> resourceGroupMap, Map<String, Subnet> subnetMap) {
        if (ListTool.isEmpty(models)) {
            cloudRedisRepository.removeByVid(vendor.getId(), region, userId);
            return;
        }
        Map<String, CloudRedis> map = Optional
                .ofNullable(cloudRedisRepository.listByVendorId(vendor.getId(), region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getRedisUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (RedisModel model : models) {
            CloudRedis entity = new CloudRedis();
            if (map.containsKey(model.getRedisUuid().toLowerCase())) {
                entity = map.get(model.getRedisUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setRegionId(region);
                if (!StringUtils.isEmpty(model.getSubnetUuid())) {
                    Subnet subnet = subnetMap.get(model.getSubnetUuid().toLowerCase());
                    if (!ObjectUtils.isEmpty(subnet)) {
                        entity.setSubnetId(subnet.getId());
                        entity.setVpcId(subnet.getVpcId());
                    }
                }
                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
                cloudRedisRepository.update(entity);
                //同步服务器防火墙规则
                syncCloudRedisFirewallRule(model.getRedisFirewallRuleModels(), entity.getId());
                map.remove(model.getRedisUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setVendorId(vendor.getId());
            if (!StringUtils.isEmpty(model.getSubnetUuid())) {
                Subnet subnet = subnetMap.get(model.getSubnetUuid().toLowerCase());
                if (!ObjectUtils.isEmpty(subnet)) {
                    entity.setSubnetId(subnet.getId());
                    entity.setVpcId(subnet.getVpcId());
                }
            }
            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
            entity.setTenantId(0L);
            entity.setProjectId(0L);
            entity.setRegionId(region);
            cloudRedisRepository.save(entity);
            //同步服务器防火墙规则
            syncCloudRedisFirewallRule(model.getRedisFirewallRuleModels(), entity.getId());
            map.remove(model.getRedisUuid().toLowerCase());
        }
        for (Map.Entry<String, CloudRedis> entry : map.entrySet()) {
            cloudRedisRepository.remove(entry.getValue().getId(), userId);
        }
    }


    private void syncCloudDatabaseServer(List<AzureDatabaseServerModel> models, CloudVendor vendor, Long userId, String region, Map<String, ResourceGroup> resourceGroupMap, Map<String, ServiceLevelObjective> sloMap, Map<String, Subnet> subnetMap) {
        if (ListTool.isEmpty(models)) {
            cloudDatabaseServerRepository.removeByVid(vendor.getId(), region, userId);
            return;
        }
        Map<String, AzureDatabaseServer> map = Optional
                .ofNullable(cloudDatabaseServerRepository.listByVendorId(vendor.getId(), region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getDatabaseServerUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (AzureDatabaseServerModel model : models) {
            AzureDatabaseServer entity = new AzureDatabaseServer();
            if (map.containsKey(model.getDatabaseServerUuid().toLowerCase())) {
                entity = map.get(model.getDatabaseServerUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setRegionId(region);
                entity.setIsMaster(true);
                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
                Optional.ofNullable(sloMap.get(model.getSloModel().getUuid() + model.getSloModel().getRegionId() + model.getSloModel().getDbType())).map(slo -> slo.getId())
                        .ifPresent(entity::setSloId);
                cloudDatabaseServerRepository.update(entity);
                //同步服务器防火墙规则
                syncDbFirewallRule(model.getDbFirewallRuleModels(), entity.getId());
                //同步服务器数据库
                syncCloudDatabase(model.getAzureDatabaseModels(), entity.getId());
                //同步服务器日志文件
                syncCloudDatabaseServerLog(model.getAzureDatabaseServerLogModels(), entity.getId());
                //同步服务器配置
                syncDbConfiguration(model.getDbConfigurationModels(), entity.getId());
                //同步VnetRule
                syncDbVnetRule(model.getDbVnetRuleModels(), entity.getId(), subnetMap);

                map.remove(model.getDatabaseServerUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setVendorId(vendor.getId());
            entity.setIsMaster(true);
            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
            Optional.ofNullable(sloMap.get(model.getSloModel().getUuid().toLowerCase())).map(slo -> slo.getId())
                    .ifPresent(entity::setSloId);
            entity.setTenantId(0L);
            entity.setProjectId(0L);
            entity.setRegionId(region);
            cloudDatabaseServerRepository.save(entity);
            //同步服务器防火墙规则
            syncDbFirewallRule(model.getDbFirewallRuleModels(), entity.getId());
            //同步服务器数据库
            syncCloudDatabase(model.getAzureDatabaseModels(), entity.getId());
            //同步服务器日志文件
            syncCloudDatabaseServerLog(model.getAzureDatabaseServerLogModels(), entity.getId());
            //同步服务器配置
            syncDbConfiguration(model.getDbConfigurationModels(), entity.getId());
            //同步VnetRule
            syncDbVnetRule(model.getDbVnetRuleModels(), entity.getId(), subnetMap);

            map.remove(model.getDatabaseServerUuid().toLowerCase());
        }
        for (Map.Entry<String, AzureDatabaseServer> entry : map.entrySet()) {
            cloudDatabaseServerRepository.remove(entry.getValue().getId(), userId);
        }
    }

//    private void syncCloudDatabaseServerBind(List<AzureDatabaseServerModel> models,Map<String, AzureDatabaseServer> mysqlMap,String regionId,Long vendorId) {
//        if (ListTool.isEmpty(models)) {
//            cloudDatabaseServerRepository.listByVendorId(vendorId);
//            return;
//        }
//        Map<String, AzureDatabaseServer> map = Optional
//                .ofNullable(cloudDatabaseServerRepository.listByVendorId(vendor.getId(), region))
//                .map(entitys -> entitys.stream()
//                        .collect(Collectors.toMap(entity -> entity.getDatabaseServerUuid().toLowerCase(),
//                                entity -> entity)))
//                .orElse(Maps.newHashMap());
//        for (AzureDatabaseServerModel model : models) {
//            AzureDatabaseServer entity = new AzureDatabaseServer();
//            if (map.containsKey(model.getDatabaseServerUuid().toLowerCase())) {
//                entity = map.get(model.getDatabaseServerUuid().toLowerCase());
//                BeanUtils.copyProperties(model, entity);
//                entity.setMenderId(userId);
//                entity.setRegionId(region);
//                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
//                        .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
//                Optional.ofNullable(sloMap.get(model.getSloModel().getUuid() + model.getSloModel().getRegionId() + model.getSloModel().getDbType())).map(slo -> slo.getId())
//                        .ifPresent(entity::setSloId);
//                cloudDatabaseServerRepository.update(entity);
//                //同步服务器防火墙规则
//                syncDbFirewallRule(model.getDbFirewallRuleModels(), entity.getId());
//                //同步服务器数据库
//                syncCloudDatabase(model.getAzureDatabaseModels(), entity.getId());
//                //同步服务器日志文件
//                syncCloudDatabaseServerLog(model.getAzureDatabaseServerLogModels(), entity.getId());
//                //同步服务器配置
//                syncDbConfiguration(model.getDbConfigurationModels(), entity.getId());
//                //同步VnetRule
//                syncDbVnetRule(model.getDbVnetRuleModels(), entity.getId(),subnetMap);
//
//                map.remove(model.getDatabaseServerUuid().toLowerCase());
//                continue;
//            }
//            BeanUtils.copyProperties(model, entity);
//            entity.setCreatorId(userId);
//            entity.setVendorId(vendor.getId());
//            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
//                    .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
//            Optional.ofNullable(sloMap.get(model.getSloModel().getUuid().toLowerCase())).map(slo -> slo.getId())
//                    .ifPresent(entity::setSloId);
//            entity.setTenantId(0L);
//            entity.setProjectId(0L);
//            entity.setRegionId(region);
//            cloudDatabaseServerRepository.save(entity);
//            //同步服务器防火墙规则
//            syncDbFirewallRule(model.getDbFirewallRuleModels(), entity.getId());
//            //同步服务器数据库
//            syncCloudDatabase(model.getAzureDatabaseModels(), entity.getId());
//            //同步服务器日志文件
//            syncCloudDatabaseServerLog(model.getAzureDatabaseServerLogModels(), entity.getId());
//            //同步服务器配置
//            syncDbConfiguration(model.getDbConfigurationModels(), entity.getId());
//            //同步VnetRule
//            syncDbVnetRule(model.getDbVnetRuleModels(), entity.getId(),subnetMap);
//
//            map.remove(model.getDatabaseServerUuid().toLowerCase());
//        }
//        for (Map.Entry<String, AzureDatabaseServer> entry : map.entrySet()) {
//            cloudDatabaseServerRepository.remove(entry.getValue().getId(), userId);
//        }
//    }


    // 同步前端ip配置
    private void syncFrontEnd(List<FrontEndModel> models, CloudVendor vendor, Long slbId, Long userId, Map<String, PublicIPAddress> publicIPAddressMap, Map<String, Subnet> subnetMap) throws Exception {
        if (ListTool.isEmpty(models)) {
            frontEndRepository.removeSlbId(slbId, userId);
            return;
        }
        Map<String, FrontEnd> map = Optional
                .ofNullable(frontEndRepository.listSlbId(slbId))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (FrontEndModel model : models) {
            FrontEnd entity = new FrontEnd();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setSlbId(slbId);
                entity.setVendorId(vendor.getId());
                if (!StringUtils.isEmpty(model.getPublicIpUuid())) {
                    Optional.ofNullable(publicIPAddressMap.get(model.getPublicIpUuid().toLowerCase()))
                            .map(publicIPAddress -> publicIPAddress.getId()).ifPresent(entity::setPublicIpId);
                }
                if (!StringUtils.isEmpty(model.getSubnetUuid())) {
                    Optional.ofNullable(subnetMap.get(model.getSubnetUuid().toLowerCase()))
                            .map(subnet -> subnet.getId()).ifPresent(entity::setSubnetId);
                }
                frontEndRepository.update(entity);
                //绑定公共ip地址关系
                resourcePublicIPAddressRelationRepository.removeByResourceId(entity.getId(), AzureIpRelationType.FRONTEND.name());
                if (!StringUtils.isEmpty(model.getPublicIpUuid())) {
                    PublicIPAddress publicIPAddress = publicIPAddressMap.get(model.getPublicIpUuid().toLowerCase());
                    if (!ObjectUtils.isEmpty(publicIPAddress)) {
                        ResourcePublicIPAddressRelation relation = new ResourcePublicIPAddressRelation();
                        relation.setIpId(publicIPAddress.getId());
                        relation.setResourceId(entity.getId());
                        relation.setResourceType(AzureIpRelationType.FRONTEND.name());
                        resourcePublicIPAddressRelationRepository.save(relation);
                        //重置状态
                        publicIPAddress.setStatus(AzureTaskStatus.IN_USE.name());
                        publicIPAddressRepository.update(publicIPAddress);
                    }
                }
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setSlbId(slbId);
            entity.setVendorId(vendor.getId());
            if (!StringUtils.isEmpty(model.getPublicIpUuid())) {
                Optional.ofNullable(publicIPAddressMap.get(model.getPublicIpUuid().toLowerCase()))
                        .map(publicIPAddress -> publicIPAddress.getId()).ifPresent(entity::setPublicIpId);
            }
            if (!StringUtils.isEmpty(model.getSubnetUuid())) {
                Optional.ofNullable(subnetMap.get(model.getSubnetUuid().toLowerCase()))
                        .map(subnet -> subnet.getId()).ifPresent(entity::setSubnetId);
            }
            frontEndRepository.save(entity);
            //绑定公共ip地址关系
            resourcePublicIPAddressRelationRepository.removeByResourceId(entity.getId(), AzureIpRelationType.FRONTEND.name());
            if (!StringUtils.isEmpty(model.getPublicIpUuid())) {
                PublicIPAddress publicIPAddress = publicIPAddressMap.get(model.getPublicIpUuid().toLowerCase());
                if (!ObjectUtils.isEmpty(publicIPAddress)) {
                    ResourcePublicIPAddressRelation relation = new ResourcePublicIPAddressRelation();
                    relation.setIpId(publicIPAddress.getId());
                    relation.setResourceId(entity.getId());
                    relation.setResourceType(AzureIpRelationType.FRONTEND.name());
                    resourcePublicIPAddressRelationRepository.save(relation);
                    //重置状态
                    publicIPAddress.setStatus(AzureTaskStatus.IN_USE.name());
                    publicIPAddressRepository.update(publicIPAddress);
                }
            }
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, FrontEnd> entry : map.entrySet()) {
            this.removePublicAddressRelation(entry.getValue().getId(), AzureIpRelationType.FRONTEND);
            frontEndRepository.remove(entry.getValue().getId(), userId);
        }
    }

    // 同步后端池
    private void syncBackEnd(List<BackEndModel> models, CloudVendor vendor, Long slbId, Long userId, Map<String, CloudServer> serverMap) throws Exception {
        if (ListTool.isEmpty(models)) {
            backEndRepository.removeSlbId(slbId, userId);
            return;
        }
        Map<String, BackEnd> map = Optional
                .ofNullable(backEndRepository.listSlbId(slbId))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (BackEndModel model : models) {
            BackEnd entity = new BackEnd();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setSlbId(slbId);
                entity.setVendorId(vendor.getId());
                backEndRepository.update(entity);
                backEndVirtualMachineRepository.removeByBackEndId(entity.getId());
                for (String vmid : model.getVirtualMachineUuids()) {
                    BackEndVirtualMachine backEndVirtualMachine = new BackEndVirtualMachine();
                    backEndVirtualMachine.setBackEndId(entity.getId());
                    backEndVirtualMachine.setVirtualMachineId(serverMap.get(vmid.toLowerCase()).getId());
                    backEndVirtualMachineRepository.save(backEndVirtualMachine);
                }
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setSlbId(slbId);
            entity.setVendorId(vendor.getId());
            backEndRepository.save(entity);
            for (String vmid : model.getVirtualMachineUuids()) {
                BackEndVirtualMachine backEndVirtualMachine = new BackEndVirtualMachine();
                backEndVirtualMachine.setBackEndId(entity.getId());
                backEndVirtualMachine.setVirtualMachineId(serverMap.get(vmid.toLowerCase()).getId());
                backEndVirtualMachineRepository.save(backEndVirtualMachine);
            }
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, BackEnd> entry : map.entrySet()) {
            backEndRepository.remove(entry.getValue().getId(), userId);
        }
    }

    //前端网络池
    private void syncInboundNatPool(List<InboundNatPoolModel> models, CloudVendor vendor, Long slbId, Long userId) throws Exception {
        if (ListTool.isEmpty(models)) {
            inboundNatPoolRepository.removeSlbId(slbId, userId);
            return;
        }
        Map<String, InboundNatPool> map = Optional
                .ofNullable(inboundNatPoolRepository.listSlbId(slbId))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (InboundNatPoolModel model : models) {
            InboundNatPool entity = new InboundNatPool();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setSlbId(slbId);
                entity.setVendorId(vendor.getId());
                inboundNatPoolRepository.update(entity);
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setSlbId(slbId);
            entity.setVendorId(vendor.getId());
            inboundNatPoolRepository.save(entity);
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, InboundNatPool> entry : map.entrySet()) {
            inboundNatPoolRepository.remove(entry.getValue().getId(), userId);
        }
    }

    //运行状况探测
    private void syncProbe(List<ProbeModel> models, CloudVendor vendor, Long slbId, Long userId) throws Exception {
        if (ListTool.isEmpty(models)) {
            probeRepository.removeSlbId(slbId, userId);
            return;
        }
        Map<String, Probe> map = Optional
                .ofNullable(probeRepository.listSlbId(slbId))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (ProbeModel model : models) {
            Probe entity = new Probe();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setSlbId(slbId);
                entity.setVendorId(vendor.getId());
                probeRepository.update(entity);
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setSlbId(slbId);
            entity.setVendorId(vendor.getId());
            probeRepository.save(entity);
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, Probe> entry : map.entrySet()) {
            probeRepository.remove(entry.getValue().getId(), userId);
        }
    }

    //负载均衡规则
    private void syncLoadBalanceRule(List<LoadBalanceRuleModel> models, CloudVendor vendor, Long slbId, Long userId, Map<String, FrontEnd> frontEndMap, Map<String, BackEnd> backEndMap, Map<String, Probe> probeMap) throws Exception {
        if (ListTool.isEmpty(models)) {
            lbRuleRepository.removeSlbId(slbId, userId);
            return;
        }
        Map<String, LbRule> map = Optional
                .ofNullable(lbRuleRepository.listSlbId(slbId))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (LoadBalanceRuleModel model : models) {
            LbRule entity = new LbRule();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setSlbId(slbId);
                entity.setVendorId(vendor.getId());
                if (!StringUtils.isEmpty(model.getFrontEndUuid())) {
                    Optional.ofNullable(frontEndMap.get(model.getFrontEndUuid().toLowerCase()))
                            .map(ent -> ent.getId()).ifPresent(entity::setFrontEndId);
                }
                if (!StringUtils.isEmpty(model.getBackEndUuid())) {
                    Optional.ofNullable(backEndMap.get(model.getBackEndUuid().toLowerCase()))
                            .map(ent -> ent.getId()).ifPresent(entity::setBackEndId);
                }
                if (!StringUtils.isEmpty(model.getProbeUuid())) {
                    Optional.ofNullable(probeMap.get(model.getProbeUuid().toLowerCase()))
                            .map(ent -> ent.getId()).ifPresent(entity::setProbeId);
                }
                lbRuleRepository.update(entity);
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setSlbId(slbId);
            entity.setVendorId(vendor.getId());
            if (!StringUtils.isEmpty(model.getFrontEndUuid())) {
                Optional.ofNullable(frontEndMap.get(model.getFrontEndUuid().toLowerCase()))
                        .map(ent -> ent.getId()).ifPresent(entity::setFrontEndId);
            }
            if (!StringUtils.isEmpty(model.getBackEndUuid())) {
                Optional.ofNullable(backEndMap.get(model.getBackEndUuid().toLowerCase()))
                        .map(ent -> ent.getId()).ifPresent(entity::setBackEndId);
            }
            if (!StringUtils.isEmpty(model.getProbeUuid())) {
                Optional.ofNullable(probeMap.get(model.getProbeUuid().toLowerCase()))
                        .map(ent -> ent.getId()).ifPresent(entity::setProbeId);
            }
            lbRuleRepository.save(entity);
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, LbRule> entry : map.entrySet()) {
            lbRuleRepository.remove(entry.getValue().getId(), userId);
        }
    }


    //入站Nat规则
    private void syncInboundNatRule(List<InboundNatRuleModel> models, CloudVendor vendor, Long slbId, Long userId, Map<String, FrontEnd> frontEndMap) throws Exception {
        if (ListTool.isEmpty(models)) {
            inboundNatRuleRepository.removeSlbId(slbId, userId);
            return;
        }
        Map<String, InboundNatRule> map = Optional
                .ofNullable(inboundNatRuleRepository.listSlbId(slbId))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (InboundNatRuleModel model : models) {
            InboundNatRule entity = new InboundNatRule();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setSlbId(slbId);
                entity.setVendorId(vendor.getId());
                Optional.ofNullable(frontEndMap.get(model.getFrontEndUuid().toLowerCase()))
                        .map(ent -> ent.getId()).ifPresent(entity::setFrontEndId);
                inboundNatRuleRepository.update(entity);
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setSlbId(slbId);
            entity.setVendorId(vendor.getId());
            Optional.ofNullable(frontEndMap.get(model.getFrontEndUuid().toLowerCase()))
                    .map(ent -> ent.getId()).ifPresent(entity::setFrontEndId);
            inboundNatRuleRepository.save(entity);
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, InboundNatRule> entry : map.entrySet()) {
            inboundNatRuleRepository.remove(entry.getValue().getId(), userId);
        }
    }

    private void syncSlb(List<SlbModel> models, CloudVendor vendor, Long userId, String region, Map<String, ResourceGroup> resourceGroupMap, Map<String, PublicIPAddress> publicIPAddressMap, Map<String, CloudServer> serverMap, Map<String, Subnet> subnetMap) throws Exception {
        if (ListTool.isEmpty(models)) {
            slbRepository.removeByVid(vendor.getId(), region, userId);
            return;
        }
        Map<String, Slb> map = Optional
                .ofNullable(slbRepository.listByVendorId(vendor.getId(), region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (SlbModel model : models) {
            Slb entity = new Slb();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setRegionId(region);
                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
                slbRepository.update(entity);
                map.remove(model.getUuid().toLowerCase());
                // 同步前端ip配置
                syncFrontEnd(model.getFrontEndModels(), vendor, entity.getId(), userId, publicIPAddressMap, subnetMap);
                // 同步后端池
                syncBackEnd(model.getBackEndModels(), vendor, entity.getId(), userId, serverMap);
                //前端网络池
                syncInboundNatPool(model.getInboundNatPoolModels(), vendor, entity.getId(), userId);
                //运行状况探测
                syncProbe(model.getProbeModels(), vendor, entity.getId(), userId);
                Map<String, FrontEnd> frontEndMap = Optional
                        .ofNullable(frontEndRepository.listSlbId(entity.getId()))
                        .map(entitys -> entitys.stream()
                                .collect(Collectors.toMap(ent -> ent.getUuid().toLowerCase(),
                                        ent -> ent)))
                        .orElse(Maps.newHashMap());
                Map<String, BackEnd> backEndMap = Optional
                        .ofNullable(backEndRepository.listSlbId(entity.getId()))
                        .map(entitys -> entitys.stream()
                                .collect(Collectors.toMap(ent -> ent.getUuid().toLowerCase(),
                                        ent -> ent)))
                        .orElse(Maps.newHashMap());
                Map<String, Probe> probeMap = Optional
                        .ofNullable(probeRepository.listSlbId(entity.getId()))
                        .map(entitys -> entitys.stream()
                                .collect(Collectors.toMap(ent -> ent.getUuid().toLowerCase(),
                                        ent -> ent)))
                        .orElse(Maps.newHashMap());
                //负载均衡规则
                syncLoadBalanceRule(model.getLoadBalanceRuleModels(), vendor, entity.getId(), userId, frontEndMap, backEndMap, probeMap);
                //入站Nat规则
                syncInboundNatRule(model.getInboundNatRuleModels(), vendor, entity.getId(), userId, frontEndMap);

                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setVendorId(vendor.getId());
            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
            entity.setTenantId(0L);
            entity.setProjectId(0L);
            entity.setRegionId(region);
            slbRepository.save(entity);
            map.remove(model.getUuid().toLowerCase());
            // 同步前端ip配置
            syncFrontEnd(model.getFrontEndModels(), vendor, entity.getId(), userId, publicIPAddressMap, subnetMap);
            // 同步后端池
            syncBackEnd(model.getBackEndModels(), vendor, entity.getId(), userId, serverMap);
            //前端网络池
            syncInboundNatPool(model.getInboundNatPoolModels(), vendor, entity.getId(), userId);
            //运行状况探测
            syncProbe(model.getProbeModels(), vendor, entity.getId(), userId);
            Map<String, FrontEnd> frontEndMap = Optional
                    .ofNullable(frontEndRepository.listSlbId(entity.getId()))
                    .map(entitys -> entitys.stream()
                            .collect(Collectors.toMap(ent -> ent.getUuid().toLowerCase(),
                                    ent -> ent)))
                    .orElse(Maps.newHashMap());
            Map<String, BackEnd> backEndMap = Optional
                    .ofNullable(backEndRepository.listSlbId(entity.getId()))
                    .map(entitys -> entitys.stream()
                            .collect(Collectors.toMap(ent -> ent.getUuid().toLowerCase(),
                                    ent -> ent)))
                    .orElse(Maps.newHashMap());
            Map<String, Probe> probeMap = Optional
                    .ofNullable(probeRepository.listSlbId(entity.getId()))
                    .map(entitys -> entitys.stream()
                            .collect(Collectors.toMap(ent -> ent.getUuid().toLowerCase(),
                                    ent -> ent)))
                    .orElse(Maps.newHashMap());
            //负载均衡规则
            syncLoadBalanceRule(model.getLoadBalanceRuleModels(), vendor, entity.getId(), userId, frontEndMap, backEndMap, probeMap);
            //入站Nat规则
            syncInboundNatRule(model.getInboundNatRuleModels(), vendor, entity.getId(), userId, frontEndMap);
        }
        for (Map.Entry<String, Slb> entry : map.entrySet()) {
            slbRepository.remove(entry.getValue().getId(), userId);
        }
    }

    private void syncPublicIpAddress(List<PublicIPAddressModel> models, CloudVendor vendor, Long userId, String region, Map<String, ResourceGroup> resourceGroupMap) throws Exception {
        if (ListTool.isEmpty(models)) {
            publicIPAddressRepository.removeByVid(vendor.getId(), region, userId);
            return;
        }
        Map<String, PublicIPAddress> map = Optional
                .ofNullable(publicIPAddressRepository.listByVendorId(vendor.getId(), region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (PublicIPAddressModel model : models) {
            PublicIPAddress entity = new PublicIPAddress();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setRegionId(region);
                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
                publicIPAddressRepository.update(entity);
                //删除公共ip绑定关系
                resourcePublicIPAddressRelationRepository.removeByIpId(entity.getId());
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setVendorId(vendor.getId());
            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
            entity.setTenantId(0L);
            entity.setProjectId(0L);
            entity.setRegionId(region);
            publicIPAddressRepository.save(entity);
            //删除公共ip绑定关系
            resourcePublicIPAddressRelationRepository.removeByIpId(entity.getId());
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, PublicIPAddress> entry : map.entrySet()) {
            resourcePublicIPAddressRelationRepository.removeByIpId(entry.getValue().getId());
            publicIPAddressRepository.remove(entry.getValue().getId(), userId);
        }
    }

    private void syncAvailabilitySet(List<AvailabilitySetModel> models, CloudVendor vendor, Long userId, String region, Map<String, ResourceGroup> resourceGroupMap) throws Exception {
        if (ListTool.isEmpty(models)) {
            availabilitySetRepository.removeByVid(vendor.getId(), region, userId);
            return;
        }
        Map<String, AvailabilitySet> map = Optional
                .ofNullable(availabilitySetRepository.listByVendorId(vendor.getId(), region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (AvailabilitySetModel model : models) {
            AvailabilitySet entity = new AvailabilitySet();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setRegionId(region);
                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
                availabilitySetRepository.update(entity);
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setVendorId(vendor.getId());
            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
            entity.setTenantId(0L);
            entity.setProjectId(0L);
            entity.setRegionId(region);
            availabilitySetRepository.save(entity);
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, AvailabilitySet> entry : map.entrySet()) {
            availabilitySetRepository.remove(entry.getValue().getId(), userId);
        }
    }

    private void syncStorageAccount(List<StorageAccountModel> models, CloudVendor vendor, Long userId, String region, Map<String, ResourceGroup> resourceGroupMap) {
        if (ListTool.isEmpty(models)) {
            List<StorageAccount> storageAccounts = storageAccountRepository.listByVendorId(vendor.getId(), region);
            for (StorageAccount account : storageAccounts) {
                List<Container> containers = containerRepository.listByCondition(vendor.getId(), account.getId());
                for (Container container : containers) {
                    containerRepository.remove(container.getId(), userId);
                    blobRepository.removeByContainerId(container.getId(), userId);
                }
            }
            storageAccountRepository.removeByVid(vendor.getId(), region, userId);
            return;
        }
        Map<String, StorageAccount> map = Optional
                .ofNullable(storageAccountRepository.listByVendorId(vendor.getId(), region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (StorageAccountModel model : models) {
            StorageAccount entity = new StorageAccount();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setRegionId(region);
                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
                storageAccountRepository.update(entity);
                //同步容器
                this.syncContainer(entity.getId(), model.getContainers(), vendor.getId(), userId);
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setVendorId(vendor.getId());
            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
            entity.setTenantId(0L);
            entity.setProjectId(0L);
            entity.setRegionId(region);
            storageAccountRepository.save(entity);
            //同步容器
            this.syncContainer(entity.getId(), model.getContainers(), vendor.getId(), userId);
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, StorageAccount> entry : map.entrySet()) {
            Long id = entry.getValue().getId();
            List<Container> containers = containerRepository.listByCondition(vendor.getId(), id);
            for (Container container : containers) {
                containerRepository.remove(container.getId(), userId);
                blobRepository.removeByContainerId(container.getId(), userId);
            }
            storageAccountRepository.remove(id, userId);
        }
    }

    /**
     * 同步容器
     *
     * @param accountId
     * @param containerModels
     * @param vendorId
     * @param managerId
     */
    public void syncContainer(Long accountId, List<ContainerModel> containerModels, Long vendorId, Long managerId) {
        if (ListTool.isEmpty(containerModels)) {
            List<Container> containers = containerRepository.listByCondition(vendorId, accountId);
            for (Container container : containers) {
                blobRepository.removeByContainerId(container.getId(), managerId);
            }
            containerRepository.removeByAccountId(accountId, managerId);
            return;
        }
        List<Container> containers = containerRepository.listByCondition(vendorId, accountId);
        Map<String, Container> containerMap = containers.stream().collect(Collectors.toMap(Container::getName, Function.identity(), (v1, v2) -> v2));
        for (ContainerModel model : containerModels) {
            List<BlobModel> blobs = model.getBlobs();
            List<BlobModel> snapshotBlobs = model.getSnapshots();
            Container container = new Container();
            if (containerMap.containsKey(model.getName())) {
                container = containerMap.get(model.getName());
                BeanUtils.copyProperties(model, container);
                container.setMenderId(managerId);
                containerRepository.update(container);
            } else {
                BeanUtils.copyProperties(model, container);
                container.setCreatorId(managerId);
                container.setGmtCreate(new Date());
                container.setVendorId(vendorId);
                container.setStorageAccountId(accountId);
                container.setTenantId(0L);
                container.setProjectId(0L);
                containerRepository.save(container);
            }
            syncBlobs(container.getId(), blobs, vendorId, managerId);
            syncBlobSnapshots(container.getId(), snapshotBlobs, vendorId, managerId);
            containerMap.remove(model.getName());
        }
        for (Map.Entry<String, Container> entry : containerMap.entrySet()) {
            Long containerId = entry.getValue().getId();
            containerRepository.remove(containerId, managerId);
            blobRepository.removeByContainerId(containerId, managerId);
        }
    }

    /**
     * 同步blob
     *
     * @param containerId
     * @param blobModels
     * @param vendorId
     * @param managerId
     */
    public void syncBlobs(Long containerId, List<BlobModel> blobModels, Long vendorId, Long managerId) {
        if (ListTool.isEmpty(blobModels)) {
            blobRepository.removeByContainerId(containerId, managerId);
            return;
        }
        List<Blob> blobs = blobRepository.listByCondition(vendorId, containerId, false);
        Map<String, Blob> blobMap = blobs.stream().collect(Collectors.toMap(Blob::getName, Function.identity(), (v1, v2) -> v2));
        for (BlobModel model : blobModels) {
            Blob blob = new Blob();
            if (blobMap.containsKey(model.getName())) {
                blob = blobMap.get(model.getName());
                BeanUtils.copyProperties(model, blob);
                blob.setMenderId(managerId);
                blobRepository.update(blob);
            } else {
                BeanUtils.copyProperties(model, blob);
                blob.setCreatorId(managerId);
                blob.setGmtCreate(new Date());
                blob.setVendorId(vendorId);
                blob.setTenantId(0L);
                blob.setProjectId(0L);
                blob.setContainerId(containerId);
                blobRepository.save(blob);
            }
            blobMap.remove(model.getName());
        }
        for (Map.Entry<String, Blob> entry : blobMap.entrySet()) {
            Long blobId = entry.getValue().getId();
            String blobName = entry.getValue().getName();
            blobRepository.removeSnapshot(blobName, containerId, managerId);
            blobRepository.remove(blobId, managerId);
        }
    }

    /**
     * 同步blob快照
     *
     * @param containerId
     * @param blobModels
     * @param vendorId
     * @param managerId
     */
    public void syncBlobSnapshots(Long containerId, List<BlobModel> blobModels, Long vendorId, Long managerId) {
        if (ListTool.isEmpty(blobModels)) {
            blobRepository.removeByContainerId(containerId, true, managerId);
            return;
        }
        List<Blob> blobs = blobRepository.listByCondition(vendorId, containerId, true);
        Map<String, Blob> blobMap = blobs.stream().collect(Collectors.toMap(b -> b.getName() + b.getSnapshotID(), Function.identity(), (v1, v2) -> v2));
        for (BlobModel model : blobModels) {
            Blob blob = new Blob();
            if (blobMap.containsKey(model.getName() + model.getSnapshotID())) {
                blob = blobMap.get(model.getName() + model.getSnapshotID());
                BeanUtils.copyProperties(model, blob);
                blob.setMenderId(managerId);
                blobRepository.update(blob);
            } else {
                BeanUtils.copyProperties(model, blob);
                blob.setCreatorId(managerId);
                blob.setGmtCreate(new Date());
                blob.setVendorId(vendorId);
                blob.setTenantId(0L);
                blob.setProjectId(0L);
                blob.setContainerId(containerId);
                blobRepository.save(blob);
            }
            blobMap.remove(model.getName() + model.getSnapshotID());
        }
        for (Map.Entry<String, Blob> entry : blobMap.entrySet()) {
            Long blobId = entry.getValue().getId();
            blobRepository.remove(blobId, managerId);
        }
    }

    private void syncDdosProtectionPlan(List<DdosProtectionPlanModel> models, CloudVendor vendor, Long userId, String region, Map<String, ResourceGroup> resourceGroupMap) {
        if (ListTool.isEmpty(models)) {
            planRepository.removeByVid(vendor.getId(), region, userId);
            return;
        }
        Map<String, DdosProtectionPlan> map = Optional
                .ofNullable(planRepository.listByVendorId(vendor.getId(), region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getDdosUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (DdosProtectionPlanModel model : models) {
            DdosProtectionPlan entity = new DdosProtectionPlan();
            if (map.containsKey(model.getDdosUuid().toLowerCase())) {
                entity = map.get(model.getDdosUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setRegionId(region);
                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
                planRepository.update(entity);
                map.remove(model.getDdosUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setVendorId(vendor.getId());
            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
            entity.setTenantId(0L);
            entity.setProjectId(0L);
            entity.setRegionId(region);
            planRepository.save(entity);
            map.remove(model.getDdosUuid().toLowerCase());
        }
        for (Map.Entry<String, DdosProtectionPlan> entry : map.entrySet()) {
            Long id = entry.getValue().getId();
            planRepository.remove(id, userId);
        }
    }

    private void syncDdosCustomPolicie(List<DdosCustomPolicieModel> models, CloudVendor vendor, Long userId, String region, Map<String, ResourceGroup> resourceGroupMap) {
        if (ListTool.isEmpty(models)) {
            policieRepository.removeByVid(vendor.getId(), region, userId);
            return;
        }
        Map<String, DdosCustomPolicie> map = Optional
                .ofNullable(policieRepository.listByVendorId(vendor.getId(), region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getPolicieUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (DdosCustomPolicieModel model : models) {
            DdosCustomPolicie entity = new DdosCustomPolicie();
            if (map.containsKey(model.getPolicieUuid().toLowerCase())) {
                entity = map.get(model.getPolicieUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setRegionId(region);
                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
                policieRepository.update(entity);
                map.remove(model.getPolicieUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setVendorId(vendor.getId());
            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
            entity.setTenantId(0L);
            entity.setProjectId(0L);
            entity.setRegionId(region);
            policieRepository.save(entity);
            map.remove(model.getPolicieUuid().toLowerCase());
        }
        for (Map.Entry<String, DdosCustomPolicie> entry : map.entrySet()) {
            Long id = entry.getValue().getId();
            policieRepository.remove(id, userId);
        }
    }


    private void syncBatchAccount(List<BatchAccountModel> models, CloudVendor vendor, Long userId, String region, Map<String, ResourceGroup> resourceGroupMap, Map<String, StorageAccount> storageAccountMap) {
        if (ListTool.isEmpty(models)) {
            batchAccountRepository.removeByVid(vendor.getId(), region, userId);
            return;
        }
        Map<String, BatchAccount> map = Optional
                .ofNullable(batchAccountRepository.listByVendorId(vendor.getId(), region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (BatchAccountModel model : models) {
            BatchAccount entity = new BatchAccount();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setRegionId(region);
                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
                Optional.ofNullable(storageAccountMap.get(model.getStorageAccountUuid().toLowerCase()))
                        .map(storageAccount -> storageAccount.getId()).ifPresent(entity::setStorageAccountId);
                batchAccountRepository.update(entity);
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setCreatorId(userId);
            entity.setVendorId(vendor.getId());
            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
            Optional.ofNullable(storageAccountMap.get(model.getStorageAccountUuid().toLowerCase()))
                    .map(storageAccount -> storageAccount.getId()).ifPresent(entity::setStorageAccountId);
            entity.setTenantId(0L);
            entity.setProjectId(0L);
            entity.setRegionId(region);
            batchAccountRepository.save(entity);
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, BatchAccount> entry : map.entrySet()) {
            batchAccountRepository.remove(entry.getValue().getId(), userId);
        }
    }

    private void syncZone(CloudVendor vendor, Long userId, Region region) throws Exception {
        // azure的zone和region 数据相同
        List<Zone> zones = zoneRepository.listByZoneId(region.getRegionId(), vendor.getId());
        if (CollectionUtils.isEmpty(zones)) {
            Zone zone = new Zone();
            zone.setName(region.getName());
            zone.setZoneId(region.getRegionId());
            zone.setRegionId(region.getRegionId());
            zone.setVendorId(vendor.getId());
            zoneRepository.save(zone);
            syncPoolGroups(zone, vendor, userId, region.getRegionId());
        }
    }

    private void syncPoolGroups(Zone zone, CloudVendor vendor, Long userId, String regionId) throws Exception {
        String name = vendor.getName() + "_" + regionId + "_" + zone.getZoneId();
        PoolGroup poolGroup = poolGroupRepository.getByRegion(regionId, zone.getZoneId(), vendor.getId(), "COMPUTER");
        if (null == poolGroup) {
            // 创建公有云资源池
            poolGroup = new PoolGroup();
            poolGroup.setAvailablitiyZone(zone.getZoneId());
            poolGroup.setRegion(regionId);
            poolGroup.setName(name);
            poolGroup.setRemark(name);
            poolGroup.setVendorId(vendor.getId());
//            poolGroup.setBindingPolicy("share");
            poolGroup.setBindingPolicy(PoolGroup.BindingPolicy.exclusive.name());
            poolGroup.setCategory("COMPUTER");
            poolGroup.setParentId(0L);
            poolGroup.setCreatorId(userId);
            poolGroup.setMenderId(userId);
            poolGroup.setIsPublic(true);
            poolGroupRepository.save(poolGroup);
        }
    }

    /**
     * 虚拟机网络接口
     *
     * @param models
     * @param vendor
     * @param userId
     * @param groupMap
     * @throws Exception
     */
    private void syncNetworkInterface(List<NetworkInterfaceModel> models, CloudVendor vendor, Long userId, Map<String, SecurityGroup> groupMap, Map<String, Vpc> vpcMap, Map<String, CloudServer> serverMap, Map<String, Subnet> subnetMap, String region, Map<String, PublicIPAddress> publicIPAddressMap, Map<String, ResourceGroup> resourceGroupMap) throws Exception {
        if (ListTool.isEmpty(models)) {
            networkInterfaceRepository.removeByVid(vendor.getId(), userId, region);
            return;
        }
        Map<String, NetworkInterface> map = Optional
                .ofNullable(networkInterfaceRepository.listByVendorId(vendor.getId(), region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getNetworkInterfaceUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (NetworkInterfaceModel model : models) {
            NetworkInterface networkInterface = new NetworkInterface();
            if (map.containsKey(model.getNetworkInterfaceUuid().toLowerCase())) {
                networkInterface = map.get(model.getNetworkInterfaceUuid().toLowerCase());
                BeanUtils.copyProperties(model, networkInterface);
                networkInterface.setMenderId(userId);
                Optional.ofNullable(model.getSecurityGroupUuid()).map(sgUuid -> groupMap.get(sgUuid.toLowerCase()))
                        .map(securityGroup -> securityGroup.getId()).ifPresent(networkInterface::setSecurityGroupId);
                Optional.ofNullable(model.getNetworkUuid()).map(networkUuid -> vpcMap.get(networkUuid.toLowerCase()))
                        .map(vpc -> vpc.getId()).ifPresent(networkInterface::setVpcId);
                Optional.ofNullable(model.getSubnetUuid()).map(subnetUuid -> subnetMap.get(subnetUuid.toLowerCase()))
                        .map(subnet -> subnet.getId()).ifPresent(networkInterface::setSubnetId);
                Optional.ofNullable(model.getVirtualMachineUuid())
                        .map(virtualMachineUuid -> serverMap.get(virtualMachineUuid.toLowerCase()))
                        .map(server -> server.getId()).ifPresent(networkInterface::setServerId);
                Optional.ofNullable(resourceGroupMap.get(model.getAzureResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(networkInterface::setResourceGroupId);
                networkInterface.setRegionId(region);
                networkInterfaceRepository.update(networkInterface);
                //同步ip配置
                this.syncNicIpConfiguration(networkInterface, model.getNicIpConfigurationModels(), publicIPAddressMap);
                map.remove(model.getNetworkInterfaceUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, networkInterface);
            networkInterface.setCreatorId(userId);
            networkInterface.setVendorId(vendor.getId());
            Optional.ofNullable(model.getSecurityGroupUuid()).map(sgUuid -> groupMap.get(sgUuid.toLowerCase()))
                    .map(securityGroup -> securityGroup.getId()).ifPresent(networkInterface::setSecurityGroupId);
            Optional.ofNullable(model.getNetworkUuid()).map(networkUuid -> vpcMap.get(networkUuid.toLowerCase()))
                    .map(vpc -> vpc.getId()).ifPresent(networkInterface::setVpcId);
            Optional.ofNullable(model.getSubnetUuid()).map(subnetUuid -> subnetMap.get(subnetUuid.toLowerCase()))
                    .map(subnet -> subnet.getId()).ifPresent(networkInterface::setSubnetId);
            Optional.ofNullable(model.getVirtualMachineUuid())
                    .map(virtualMachineUuid -> serverMap.get(virtualMachineUuid.toLowerCase()))
                    .map(server -> server.getId()).ifPresent(networkInterface::setServerId);
            Optional.ofNullable(resourceGroupMap.get(model.getAzureResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(networkInterface::setResourceGroupId);
            networkInterface.setRegionId(region);
            networkInterface.setTenantId(0L);
            networkInterface.setProjectId(0L);
            networkInterfaceRepository.save(networkInterface);
            //同步ip配置
            this.syncNicIpConfiguration(networkInterface, model.getNicIpConfigurationModels(), publicIPAddressMap);
            map.remove(model.getNetworkInterfaceUuid().toLowerCase());
        }
        for (Map.Entry<String, NetworkInterface> entry : map.entrySet()) {
            networkInterfaceRepository.delete(entry.getValue().getId(), userId);
        }
    }

    private void syncNicIpConfiguration(NetworkInterface networkInterface, List<NicIpConfigurationModel> models, Map<String, PublicIPAddress> publicIPAddressMap) throws Exception {
        if (ListTool.isEmpty(models)) {
            nicIpConfigurationRepository.deleteByNetworkInterfaceId(networkInterface.getId());
            return;
        }

        Map<String, NicIpConfiguration> map = new HashMap<>();
        List<NicIpConfiguration> nicIpConfigurations = nicIpConfigurationRepository.listByNetworkInterfaceId(networkInterface.getId());
        for (NicIpConfiguration nicIpConfiguration : nicIpConfigurations) {
            map.put(nicIpConfiguration.getUuid().toLowerCase(), nicIpConfiguration);
        }
        for (NicIpConfigurationModel model : models) {
            NicIpConfiguration entity = new NicIpConfiguration();
            if (map.containsKey(model.getUuid().toLowerCase())) {
                entity = map.get(model.getUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setNetworkInterfaceId(networkInterface.getId());
                entity.setVpcId(networkInterface.getVpcId());
                entity.setSubnetId(networkInterface.getSubnetId());
                nicIpConfigurationRepository.update(entity);
                //绑定公共ip地址关系
                resourcePublicIPAddressRelationRepository.removeByResourceId(entity.getId(), AzureIpRelationType.NICIPCONFIGURATION.name());
                if (!StringUtils.isEmpty(model.getPublicIpAddressUuid())) {
                    PublicIPAddress publicIPAddress = publicIPAddressMap.get(model.getPublicIpAddressUuid().toLowerCase());
                    if (!ObjectUtils.isEmpty(publicIPAddress)) {
                        resourcePublicIPAddressRelationRepository.removeByIpId(publicIPAddress.getId());
                        //更新公共IP地址
                        entity.setPublicIpAddressId(publicIPAddress.getId());
                        nicIpConfigurationRepository.update(entity);
                        ResourcePublicIPAddressRelation relation = new ResourcePublicIPAddressRelation();
                        relation.setIpId(publicIPAddress.getId());
                        relation.setResourceId(entity.getId());
                        relation.setResourceType(AzureIpRelationType.NICIPCONFIGURATION.name());
                        resourcePublicIPAddressRelationRepository.save(relation);
                        //重置状态
                        publicIPAddress.setStatus(AzureTaskStatus.IN_USE.name());
                        publicIPAddressRepository.update(publicIPAddress);
                    }
                }
                map.remove(model.getUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setNetworkInterfaceId(networkInterface.getId());
            entity.setVpcId(networkInterface.getVpcId());
            entity.setSubnetId(networkInterface.getSubnetId());
            nicIpConfigurationRepository.save(entity);
            //绑定公共ip地址关系
            resourcePublicIPAddressRelationRepository.removeByResourceId(entity.getId(), AzureIpRelationType.NICIPCONFIGURATION.name());
            if (!StringUtils.isEmpty(model.getPublicIpAddressUuid())) {
                PublicIPAddress publicIPAddress = publicIPAddressMap.get(model.getPublicIpAddressUuid().toLowerCase());
                if (!ObjectUtils.isEmpty(publicIPAddress)) {
                    resourcePublicIPAddressRelationRepository.removeByIpId(publicIPAddress.getId());
                    //更新公共IP地址
                    entity.setPublicIpAddressId(publicIPAddress.getId());
                    nicIpConfigurationRepository.update(entity);
                    ResourcePublicIPAddressRelation relation = new ResourcePublicIPAddressRelation();
                    relation.setIpId(publicIPAddress.getId());
                    relation.setResourceId(entity.getId());
                    relation.setResourceType(AzureIpRelationType.NICIPCONFIGURATION.name());
                    resourcePublicIPAddressRelationRepository.save(relation);
                    //重置状态
                    publicIPAddress.setStatus(AzureTaskStatus.IN_USE.name());
                    publicIPAddressRepository.update(publicIPAddress);
                }
            }
            map.remove(model.getUuid().toLowerCase());
        }
        for (Map.Entry<String, NicIpConfiguration> entry : map.entrySet()) {
            this.removePublicAddressRelation(entry.getValue().getId(), AzureIpRelationType.NICIPCONFIGURATION);
            nicIpConfigurationRepository.delete(entry.getValue().getId());
        }

    }


    /**
     * 同步虚拟机规格
     *
     * @param models
     * @param vendorId
     * @throws Exception
     */
    private void syncFlavor(List<FlavorModel> models, Long vendorId, String region) {
        if (ListTool.isEmpty(models)) {
            flavorRepository.removeByVid(vendorId, region);
            return;
        }
        Map<String, Flavor> map = Optional
                .ofNullable(flavorRepository.listByVendorId(vendorId, region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getFlavorUuid() + entity.getRegionId(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (FlavorModel model : models) {
            Flavor entity = new Flavor();
            if (map.containsKey(model.getFlavorUuid() + model.getRegionId())) {
                entity = map.get(model.getFlavorUuid() + model.getRegionId());
                BeanUtils.copyProperties(model, entity);
                //二次处理，对于之前存在的平台数据，没有状态信息重新插入下架状态
                if (StringUtils.isEmpty(entity.getStatus())) {
                    entity.setStatus("AVAILABLE");
                }
                entity.setAvailable(model.getAvailable());
                flavorRepository.update(entity);
                map.remove(model.getFlavorUuid() + model.getRegionId());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.setVendorId(vendorId);
            entity.setStatus("AVAILABLE");
            entity.setAvailable(model.getAvailable());
            flavorRepository.save(entity);
            map.remove(model.getFlavorUuid() + model.getRegionId());
        }
        for (Map.Entry<String, Flavor> entry : map.entrySet()) {
            flavorRepository.delete(entry.getValue().getId());
        }
    }

    /**
     * 同步安全组
     *
     * @param models
     * @param vendor
     * @param userId
     * @throws Exception
     */
    private void syncSecurityGroup(List<SecurityGroupModel> models, CloudVendor vendor, Long userId, String regionId, Map<String, ResourceGroup> resourceGroupMap) throws Exception {
        if (ListTool.isEmpty(models)) {
            securityGroupRepository.removeByVid(vendor.getId(), regionId, userId);
            return;
        }
        Map<String, SecurityGroup> map = Optional
                .ofNullable(securityGroupRepository.listByVendorId(vendor.getId(), regionId, null))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getGroupUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (SecurityGroupModel model : models) {
            SecurityGroup entity = new SecurityGroup();
            if (map.containsKey(model.getGroupUuid().toLowerCase())) {
                entity = map.get(model.getGroupUuid().toLowerCase());
                BeanUtils.copyProperties(model, entity);
                entity.setMenderId(userId);
                entity.setRegionId(regionId);
                //字段暂时保留以后去掉
                entity.setAzureResourceGroupName(model.getResourceGroupName());
                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
                securityGroupRepository.update(entity);
                securityGroupRuleRepository.removeBySgId(entity.getId(), userId);
                for (SecurityGroupRuleModel securityGroupRuleModel : model.getModels()) {
                    SecurityGroupRule securityGroupRule = new SecurityGroupRule();
                    BeanUtils.copyProperties(securityGroupRuleModel, securityGroupRule);
                    securityGroupRule.setCreatorId(userId);
                    securityGroupRule.setVendorId(vendor.getId());
                    securityGroupRule.setGroupId(entity.getId());
                    securityGroupRule.setGroupUuid(entity.getGroupUuid());
                    securityGroupRule.setDefaultRule(securityGroupRuleModel.getDefaultRule());
                    securityGroupRuleRepository.save(securityGroupRule);
                }
                map.remove(model.getGroupUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, entity);
            entity.preSave(userId, userId, vendor.getId(), 0L, 0L);
            entity.setRegionId(regionId);
            //字段暂时保留以后去掉
            entity.setAzureResourceGroupName(model.getResourceGroupName());
            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(entity::setResourceGroupId);
            securityGroupRepository.save(entity);
            map.remove(model.getGroupUuid().toLowerCase());
            securityGroupRuleRepository.removeBySgId(entity.getId(), userId);
            for (SecurityGroupRuleModel securityGroupRuleModel : model.getModels()) {
                SecurityGroupRule securityGroupRule = new SecurityGroupRule();
                BeanUtils.copyProperties(securityGroupRuleModel, securityGroupRule);
                securityGroupRule.setCreatorId(userId);
                securityGroupRule.setVendorId(vendor.getId());
                securityGroupRule.setGroupId(entity.getId());
                securityGroupRule.setGroupUuid(entity.getGroupUuid());
                securityGroupRule.setDefaultRule(securityGroupRuleModel.getDefaultRule());
                securityGroupRuleRepository.save(securityGroupRule);
            }
        }
        // 删除不存在的安全组
        for (Map.Entry<String, SecurityGroup> entry : map.entrySet()) {
            securityGroupRepository.remove(entry.getValue().getId(), userId);
        }
    }

    /**
     * 虚拟机网络
     *
     * @param models
     * @param vendorId
     * @param userId
     * @throws Exception
     */
    private void syncVpc(List<VpcModel> models, Long vendorId, Long userId, Map<String, SecurityGroup> groupMap, Map<String, RouterTable> routerMap, String region) {
        if (ListTool.isEmpty(models)) {
            vpcRepository.deleteByVid(vendorId, region, userId);
            subnetRepository.removeByVid(vendorId, region, userId);
            return;
        }
        Map<String, Long> planMap = Optional
                .ofNullable(planRepository.listByVendorId(vendorId, region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getDdosUuid().toLowerCase(),
                                entity -> entity.getId())))
                .orElse(Maps.newHashMap());
        Map<String, Vpc> map = Optional
                .ofNullable(vpcRepository.list(vendorId, region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getVpcId().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (VpcModel model : models) {
            Vpc vpc = new Vpc();
            if (map.containsKey(model.getVpcId().toLowerCase())) {
                vpc = map.get(model.getVpcId().toLowerCase());
                BeanUtils.copyProperties(model, vpc);
                vpc.setMenderId(userId);
                vpc.setRegionId(region);
                if (StringUtils.hasText(model.getDdosPlanUuid())) {
                    vpc.setDdosPlanId(planMap.get(model.getDdosPlanUuid().toLowerCase()));
                }
                vpcRepository.update(vpc);
                // 同步子网
                this.syncSubnet(model.getSubnetModels(), vendorId, userId, model.getVpcId(), vpc.getId(),
                        model.getRegionId(), groupMap, routerMap);
                map.remove(model.getVpcId().toLowerCase());
                continue;
            }

            BeanUtils.copyProperties(model, vpc);
            if (StringUtils.hasText(model.getDdosPlanUuid())) {
                vpc.setDdosPlanId(planMap.get(model.getDdosPlanUuid().toLowerCase()));
            }
            vpc.setCreatorId(userId);
            vpc.setTenantId(0L);
            vpc.setProjectId(0L);
            vpc.setVendorId(vendorId);
            vpc.setRegionId(region);
            vpcRepository.save(vpc);
            // 同步子网
            this.syncSubnet(model.getSubnetModels(), vendorId, userId, model.getVpcId(), vpc.getId(),
                    model.getRegionId(), groupMap, routerMap);
            map.remove(model.getVpcId().toLowerCase());
        }
        for (Map.Entry<String, Vpc> entry : map.entrySet()) {
            vpcRepository.delete(entry.getValue().getId(), userId);
        }
    }

    /**
     * 子网
     *
     * @param models
     * @param vendorId
     * @param userId
     * @throws Exception
     */
    private void syncSubnet(List<SubnetModel> models, Long vendorId, Long userId, String vpcUuid, Long vpcId, String regionId, Map<String, SecurityGroup> groupMap, Map<String, RouterTable> routerMap) {
        if (ListTool.isEmpty(models)) {
            subnetRepository.removeByNetworkId(vpcId, userId);
            return;
        }
        Map<String, Subnet> map = Optional
                .ofNullable(subnetRepository.listByVpcId(vendorId, vpcUuid))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getSubnetUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (SubnetModel model : models) {
            Subnet subnet = new Subnet();
            if (map.containsKey(model.getSubnetUuid().toLowerCase())) {
                subnet = map.get(model.getSubnetUuid().toLowerCase());
                BeanUtils.copyProperties(model, subnet);
                subnet.setMenderId(userId);
                subnet.setNetworkId(vpcId);
                subnet.setVpcId(vpcId);
                subnet.setVpcUuid(vpcUuid);
                subnet.setRegionId(regionId);
                Optional.ofNullable(model.getSecurityGroupUuid()).map(sgUuid -> groupMap.get(sgUuid.toLowerCase()))
                        .map(securityGroup -> securityGroup.getId()).ifPresent(subnet::setSecurityGroupId);
                Optional.ofNullable(model.getRouterTableUuid()).map(routerTableUuid -> routerMap.get(routerTableUuid.toLowerCase()))
                        .map(routerTable -> routerTable.getId()).ifPresent(subnet::setRouterTableId);
                subnetRepository.update(subnet);
                map.remove(model.getSubnetUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, subnet);
            subnet.setCreatorId(userId);
            subnet.setVendorId(vendorId);
            subnet.setNetworkId(vpcId);
            subnet.setVpcId(vpcId);
            subnet.setVpcUuid(vpcUuid);
            subnet.setRegionId(regionId);
            Optional.ofNullable(model.getSecurityGroupUuid()).map(sgUuid -> groupMap.get(sgUuid.toLowerCase()))
                    .map(securityGroup -> securityGroup.getId()).ifPresent(subnet::setSecurityGroupId);
            Optional.ofNullable(model.getRouterTableUuid()).map(routerTableUuid -> routerMap.get(routerTableUuid.toLowerCase()))
                    .map(routerTable -> routerTable.getId()).ifPresent(subnet::setRouterTableId);
            subnetRepository.save(subnet);
            map.remove(model.getSubnetUuid().toLowerCase());
        }
        for (Map.Entry<String, Subnet> entry : map.entrySet()) {
            subnetRepository.remove(entry.getValue().getId(), userId);
        }
    }

    /**
     * 同步资源组
     *
     * @param models
     * @param vendorId
     * @param userId
     * @throws Exception
     */
    private void syncAzureResourceGroup(List<ResourceGroupModel> models, Long vendorId, Long userId, String regionId) throws Exception {
        if (ListTool.isEmpty(models)) {
            azureResourceGroupRepository.removeByVid(vendorId, userId, regionId);
            return;
        }
        Map<String, ResourceGroup> map = Optional
                .ofNullable(azureResourceGroupRepository.listByVendorId(vendorId, regionId))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getResourceGroupUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (ResourceGroupModel model : models) {
            ResourceGroup resourceGroup = new ResourceGroup();
            if (map.containsKey(model.getResourceGroupUuid().toLowerCase())) {
                resourceGroup = map.get(model.getResourceGroupUuid().toLowerCase());
                BeanUtils.copyProperties(model, resourceGroup);
                model.setGmtCreate(resourceGroup.getGmtCreate());
                resourceGroup.setMenderId(userId);
                resourceGroup.setGmtModify(new Date());
                resourceGroup.setRegionId(regionId);
                azureResourceGroupRepository.update(resourceGroup);
                map.remove(resourceGroup.getResourceGroupUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, resourceGroup);
            resourceGroup.setCreatorId(userId);
            resourceGroup.setGmtCreate(model.getGmtCreate());
            resourceGroup.setVendorId(vendorId);
            resourceGroup.setRegionId(regionId);
            resourceGroup.setTenantId(0L);
            resourceGroup.setProjectId(0L);
            azureResourceGroupRepository.save(resourceGroup);
            map.remove(resourceGroup.getResourceGroupUuid().toLowerCase());
        }
        for (Map.Entry<String, ResourceGroup> entry : map.entrySet()) {
            azureResourceGroupRepository.remove(entry.getValue().getId(), userId);
        }
    }

    private void syncSnapshot(List<SnapshotModel> models, CloudVendor vendor, Long userId, String region, Map<String, Volume> volumeMap) {
        if (ListTool.isEmpty(models)) {
            snapshotRepository.removeByVid(vendor.getId(), region, userId);
            return;
        }
        Map<String, Snapshot> map = Optional
                .ofNullable(snapshotRepository.listByVid(vendor.getId(), region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getSnapshotUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (SnapshotModel model : models) {
            Snapshot snapshot = new Snapshot();
            if (map.containsKey(model.getSnapshotUuid().toLowerCase())) {
                snapshot = map.get(model.getSnapshotUuid().toLowerCase());
                BeanUtils.copyProperties(model, snapshot);
                snapshot.setMenderId(userId);
                snapshot.setRegionId(region);
                Optional.ofNullable(model.getVolumeUuid()).map(volumeUuid -> volumeMap.get(volumeUuid.toLowerCase()))
                        .map(volume -> volume.getId()).ifPresent(snapshot::setVolumeId);
                snapshotRepository.update(snapshot);
                map.remove(model.getSnapshotUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, snapshot);
            snapshot.setGmtCreate(model.getCreateTime());
            snapshot.setCreatorId(userId);
            snapshot.setVendorId(vendor.getId());
            snapshot.setVendorType(vendor.getType());
            snapshot.setTenantId(0L);
            snapshot.setProjectId(0L);
            snapshot.setRegionId(region);
            Optional.ofNullable(model.getVolumeUuid()).map(volumeUuid -> volumeMap.get(volumeUuid.toLowerCase()))
                    .map(volume -> volume.getId()).ifPresent(snapshot::setVolumeId);
            snapshotRepository.save(snapshot);
            map.remove(snapshot.getSnapshotUuid().toLowerCase());
        }
        for (Map.Entry<String, Snapshot> entry : map.entrySet()) {
            snapshotRepository.remove(entry.getValue().getId(), userId);
        }
    }

//    /**
//     * 同步镜像
//     *
//     * @param models
//     * @param vendor
//     * @param userId
//     * @throws Exception
//     */
//    private void syncImage(List<ImageModel> models, CloudVendor vendor, Long userId, String region) {
//        if (ListTool.isEmpty(models)) {
//            vendorRelationRepository.deleteByVendorId(vendor.getId(), region);
//            // 判断是否需要删除镜像数据
//            List<Image> images = imageRepository.listByVendorType(CloudProvider.AZURE.name());
//            for (Image image : images) {
//                List<ImageVendorRelation> relations = vendorRelationRepository.listByImageId(image.getId(), region);
//                if (ListTool.isEmpty(relations)) {
//                    imageRepository.remove(image.getId(), userId);
//                }
//            }
//            return;
//        }
//        List<Image> images = imageRepository.listByVendorType(CloudProvider.AZURE.name());
//        Map<String, Image> imageMap = new HashMap<>();
//        for (Image image : images) {
//            //说明有重复数据
//            if (imageMap.containsKey(image.getImageUuid().toLowerCase())) {
//                imageRepository.remove(image.getId(), userId);
//            } else {
//                imageMap.put(image.getImageUuid().toLowerCase(), image);
//            }
//        }
//        for (ImageModel model : models) {
//            Image image = new Image();
//            if (imageMap.containsKey(model.getImageUuid().toLowerCase())) {
//                image = imageMap.get(model.getImageUuid().toLowerCase());
//                BeanUtils.copyProperties(model, image);
//                image.setMenderId(userId);
//                image.setGmtModify(new Date());
////                image.setRegionId(region);
//                image.setVendorType(vendor.getType());
//                imageRepository.update(image);
//            } else {
//                BeanUtils.copyProperties(model, image);
//                image.setCreatorId(userId);
//                image.setGmtCreate(new Date());
//                // image.setVendorId(vendor.getId());
////                image.setRegionId(region);
//                image.setVendorType(vendor.getType());
//                image.setTenantId(0L);
//                image.setProjectId(0L);
//                image.setCatalog("VM");
//                imageRepository.save(image);
//            }
//            // 处理镜像和云平台关系
//            vendorRelationRepository.deleteByCondition(vendor.getId(), image.getId(), region);
//            ImageVendorRelation relation = ImageVendorRelation.builder().vendorId(vendor.getId()).imageId(image.getId()).regionId(region)
//                    .build();
//            vendorRelationRepository.save(relation);
//        }
//        // 判断是否需要删除镜像数据
//        images = imageRepository.listByVendorType(CloudProvider.AZURE.name());
//        for (Image image : images) {
//            List<ImageVendorRelation> relations = vendorRelationRepository.listByImageId(image.getId(), region);
//            if (ListTool.isEmpty(relations)) {
//                imageRepository.remove(image.getId(), userId);
//            }
//        }
//    }

    /**
     * 同步镜像
     *
     * @param models
     * @param vendor
     * @param userId
     * @throws Exception
     */
    private void syncImage(List<ImageModel> models, CloudVendor vendor, Long userId, String region) {
        if (ListTool.isEmpty(models)) {
            imageRepository.removeByVid(vendor.getId(), region, userId);
            return;
        }
        List<Image> images = imageRepository.listByVendorId(vendor.getId(), region);
        Map<String, Image> imageMap = Maps.newHashMap();
        for (Image image : images) {
            imageMap.put(image.getImageUuid().toLowerCase(), image);
        }
        for (ImageModel model : models) {
            Image image = new Image();
            if (imageMap.containsKey(model.getImageUuid().toLowerCase())) {
                image = imageMap.get(model.getImageUuid().toLowerCase());
                BeanUtils.copyProperties(model, image);
                image.setMenderId(userId);
                image.setGmtModify(new Date());
                image.setRegionId(region);
                image.setVendorType(vendor.getType());
                imageRepository.update(image);
                imageMap.remove(image.getImageUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, image);
            image.setCreatorId(userId);
            image.setGmtCreate(new Date());
            image.setVendorId(vendor.getId());
            image.setVendorType(vendor.getType());
            image.setTenantId(0L);
            image.setProjectId(0L);
            image.setRegionId(region);
            image.setCatalog("VM");
            imageRepository.save(image);
            imageMap.remove(image.getImageUuid().toLowerCase());
        }
        for (Map.Entry<String, Image> entry : imageMap.entrySet()) {
            imageRepository.remove(entry.getValue().getId(), userId);
        }
    }

    /**
     * 同步云硬盘
     *
     * @param models
     * @param vendor
     * @param userId
     * @throws Exception
     */
    private void syncVolume(List<VolumeModel> models, CloudVendor vendor, Long userId, Map<String, CloudServer> serverMap, String region, Map<String, String> systemOsDiskMap) {
        volumeRepository.deleteRegionNull(vendor.getId());
        if (ListTool.isEmpty(models)) {
            volumeRepository.removeByVid(vendor.getId(), region, userId);
            return;
        }
        Map<String, Volume> map = Optional
                .ofNullable(volumeRepository.listByVendorId(vendor.getId(), region))
                .map(entitys -> entitys.stream()
                        .collect(Collectors.toMap(entity -> entity.getVolumeUuid().toLowerCase(),
                                entity -> entity)))
                .orElse(Maps.newHashMap());
        for (VolumeModel model : models) {
            Volume volume = new Volume();
            if (map.containsKey(model.getVolumeUuid().toLowerCase())) {
                volume = map.get(model.getVolumeUuid().toLowerCase());
                BeanUtils.copyProperties(model, volume);
                volume.setMenderId(userId);
                volume.setGmtModify(new Date());
                volume.setVendorType(vendor.getType());
                Optional.ofNullable(model.getInstanceId()).map(instanceId -> serverMap.get(instanceId.toLowerCase()))
                        .map(server -> server.getId()).ifPresent(volume::setServerId);
                if (systemOsDiskMap.containsKey(model.getVolumeUuid().toLowerCase())) {
                    volume.setBootVolume(true);
                } else {
                    volume.setBootVolume(false);
                }
                volume.setRegionId(region);
                volumeRepository.update(volume);
                map.remove(volume.getVolumeUuid().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, volume);
            volume.setCreatorId(userId);
            volume.setGmtCreate(model.getCreateTime());
            volume.setVendorId(vendor.getId());
            volume.setVendorType(vendor.getType());
            volume.setProjectId(0L);
            volume.setTenantId(0L);
            Optional.ofNullable(model.getInstanceId()).map(instanceId -> serverMap.get(instanceId.toLowerCase()))
                    .map(server -> server.getId()).ifPresent(volume::setServerId);
            if (systemOsDiskMap.containsKey(model.getVolumeUuid().toLowerCase())) {
                volume.setBootVolume(true);
            } else {
                volume.setBootVolume(false);
            }
            volume.setRegionId(region);
            volumeRepository.save(volume);
            map.remove(volume.getVolumeUuid().toLowerCase());
        }
        for (Map.Entry<String, Volume> entry : map.entrySet()) {
            volumeRepository.remove(entry.getValue().getId(), userId);
        }
    }

    /**
     * 同步虚拟机
     *
     * @param models
     * @param vendor
     * @param userId
     * @throws Exception
     */
    private void syncServer(List<ServerModel> models, CloudVendor vendor, Long userId, Region region, List<CmdbInfo> infos, Map<String, SecurityGroup> groupMap, Map<String, Flavor> flavorMap, Map<String, AvailabilitySet> availabilitySetMap, Map<String, Keypair> keypairMap, Map<String, ResourceGroup> resourceGroupMap, Map<String, Vpc> vpcMap) throws Exception {
        if (null != groupMap && groupMap.keySet().size() > 0) {
            for (String key : groupMap.keySet()) {
                serverSgroupRepository.removeBySgid(groupMap.get(key).getId());
            }
        }
        List<CloudServer> servers = cloudServerRepository.listByVid(vendor.getId(), region.getRegionId());
        // 删除 虚拟机 秘钥关联关系
        for (CloudServer cloudServer : servers) {
            serverKeyPairRepository.removeBySid(cloudServer.getId());
        }
        if (ListTool.isEmpty(models)) {
//            for (CloudServer server : servers) {
//                // cmdb：删除虚拟机
//                infos.add(CmdbInfoConvertor.getInfo(server, "delete", null));
//            }
            cloudServerRepository.removeByVid(vendor.getId(), region.getRegionId(), userId);
            // 删除资源表
            resourceRepository.removeByVidReg(vendor.getId(), region.getRegionId(), userId);
            return;
        }
        Map<String, CloudServer> serverMap = Maps.newHashMap();
        for (CloudServer server : servers) {
            // azure大坑，返回的uuid忽略大小写
            serverMap.put(server.getInstanceId().toLowerCase(), server);
        }
        for (ServerModel model : models) {
            CloudServer server = new CloudServer();
            List<CmdbRelation> relations = Lists.newArrayList();
            relations.add(new CmdbRelation(ModuleCode.REGION.name(), 1L, ListUtils.getList(region.getGuid())));
            if (serverMap.containsKey(model.getInstanceId().toLowerCase())) {
                server = serverMap.get(model.getInstanceId().toLowerCase());
                String account = server.getAccount();
                if (StringUtils.isEmpty(account)) {
                    Image image = imageRepository.getByImageUuid(server.getImageUuid());
                    if (null != image) {
                        account = image.getDefaultUser();
                    }
                }
                model.setAccount(account);
                model.setPassword(server.getPassword());
                BeanUtils.copyProperties(model, server);
                server.setMenderId(userId);
                server.setGmtModify(new Date());
                server.setGmtVmCreate(model.getGmtVmCreate());
                server.setVendorType(vendor.getType());
                server.setIsTemplate(false);
                server.setRegionId(region.getRegionId());
                server.setZone(region.getRegionId());
                server.setProps(model.getProps());
                //TODO 以后改为resourceGroupId ,暂时保留字段
                server.setAzureResourceGroupName(model.getResourceGroupName());
                // 设置cpu，内存
                if (!StringUtils.isEmpty(model.getFlavorUuid())) {
                    if (null != flavorMap.get(model.getFlavorUuid().toLowerCase())) {
                        server.setCpu(flavorMap.get(model.getFlavorUuid().toLowerCase()).getCpu());
                        server.setMemory(flavorMap.get(model.getFlavorUuid().toLowerCase()).getMemory());
                    } else {
                        logger.info("本地不存在该规格,规格{}", model.getFlavorUuid());
                    }
                } else {
                    logger.info("虚拟机规格不存在,虚拟机：{}", server.getName());
                }
                // 安全组
                List<String> securityGroupUuids = model.getSecurityGroups();
                if (!CollectionUtils.isEmpty(securityGroupUuids)) {
                    server.setSecurityGroupId(JSON.toJSONString(securityGroupUuids));
                }
                // 可用性集
                Optional.ofNullable(model.getAvailabilitySetUuid())
                        .map(availabilitySetUuid -> availabilitySetMap.get(availabilitySetUuid.toLowerCase()).getId())
                        .ifPresent(server::setAvailabilitySetId);
                // 密钥
                if (!StringUtils.isEmpty(model.getSshKey())) {
                    List<String> keys = JSONArray.parseArray(model.getSshKey(), String.class);
                    List<String> keypairName = new ArrayList<>();
                    for (String key : keys) {
                        Keypair keypair = keypairMap.get(key.toLowerCase());
                        if (null != keypair) {
                            keypairName.add(keypair.getName());
                        }
                    }
                    server.setKeypairName(JSONObject.toJSONString(keypairName));
//                    List<String> keypairName = keys.stream().map(key -> Optional
//                            .ofNullable(keypairMap.get(key.toLowerCase()))
//                            .map(keypair -> keypair.getName()).get())
//                            .collect(Collectors.toList());
//                    server.setKeypairName(JSONObject.toJSONString(keypairName));
                }
                //资源组
                Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                        .map(group -> group.getId()).ifPresent(server::setResourceGroupId);
                //vpc
                Optional.ofNullable(vpcMap.get(model.getVpcUuid().toLowerCase()))
                        .map(vpc -> vpc.getId()).ifPresent(server::setVpcId);
                cloudServerRepository.update(server);

                // 更新密钥绑定关系
                this.updateServerKeyPair(server, keypairMap);
                // 更新资源表
                updateResource(server, vendor, region.getRegionId(), userId);
                // 更新虚拟机绑定的安全组
                serverSgroupRepository.removeBySid(server.getId());
                if (!CollectionUtils.isEmpty(securityGroupUuids)) {
                    updateSGroup(server.getId(), JSON.toJSONString(securityGroupUuids), groupMap);
                }
                // CMDB更新集群数据
//                infos.add(CmdbInfoConvertor.getInfo(server, null, relations));
                serverMap.remove(model.getInstanceId().toLowerCase());
                continue;
            }
            BeanUtils.copyProperties(model, server);
            server.setCreatorId(userId);
            server.setGmtCreate(new Date());
            server.setVendorId(vendor.getId());
            server.setVendorType(vendor.getType());
            server.setProps(model.getProps());
            server.setTenantId(0L);
            server.setProjectId(0L);
            server.setIsTemplate(false);
            server.setRecycle(false);
            server.setRegionId(region.getRegionId());
            server.setZone(region.getRegionId());
            //TODO 以后改为resourceGroupId ,暂时保留字段
            server.setAzureResourceGroupName(model.getResourceGroupName());
            // 设置cpu，内存
            if (!StringUtils.isEmpty(model.getFlavorUuid())) {
                if (null != flavorMap.get(model.getFlavorUuid().toLowerCase())) {
                    server.setCpu(flavorMap.get(model.getFlavorUuid().toLowerCase()).getCpu());
                    server.setMemory(flavorMap.get(model.getFlavorUuid().toLowerCase()).getMemory());
                } else {
                    logger.info("本地不存在该规格,规格{}", model.getFlavorUuid());
                }
            } else {
                logger.info("虚拟机规格不存在,虚拟机：{}", server.getName());
            }
            // 安全组
            List<String> securityGroupUuids = model.getSecurityGroups();
            if (!CollectionUtils.isEmpty(securityGroupUuids)) {
                server.setSecurityGroupId(JSON.toJSONString(securityGroupUuids));
            }
            // 可用性集
            Optional.ofNullable(model.getAvailabilitySetUuid())
                    .map(availabilitySetUuid -> availabilitySetMap.get(availabilitySetUuid.toLowerCase()).getId())
                    .ifPresent(server::setAvailabilitySetId);
            // 密钥
            if (!StringUtils.isEmpty(model.getSshKey())) {
                List<String> keypairName = new ArrayList<>();
                List<String> keys = JSONArray.parseArray(model.getSshKey(), String.class);
                for (String key : keys) {
                    Keypair keypair = keypairMap.get(key.toLowerCase());
                    if (null != keypair) {
                        keypairName.add(keypair.getName());
                    } else {
                        logger.info("同步密钥找不到->key:{}", key);
                    }
                }
                server.setKeypairName(JSONObject.toJSONString(keypairName));
//                List<String> keypairName = keys.stream().map(key -> Optional
//                        .ofNullable(keypairMap.get(key.toLowerCase())).map(keypair -> keypair.getName()).get())
//                        .collect(Collectors.toList());
//                server.setKeypairName(JSONObject.toJSONString(keypairName));
            }
            //资源组
            Optional.ofNullable(resourceGroupMap.get(model.getResourceGroupName().toLowerCase()))
                    .map(group -> group.getId()).ifPresent(server::setResourceGroupId);
            //vpc
            Optional.ofNullable(vpcMap.get(model.getVpcUuid().toLowerCase()))
                    .map(vpc -> vpc.getId()).ifPresent(server::setVpcId);
            cloudServerRepository.save(server);
            // 更新密钥绑定关系
            this.updateServerKeyPair(server, keypairMap);
            // 更新资源表
            updateResource(server, vendor, region.getRegionId(), userId);
            // 更新虚拟机绑定的安全组
            serverSgroupRepository.removeBySid(server.getId());
            if (!CollectionUtils.isEmpty(securityGroupUuids)) {
                updateSGroup(server.getId(), JSON.toJSONString(securityGroupUuids), groupMap);
            }
            // CMDB更新集群数据
//            infos.add(CmdbInfoConvertor.getInfo(server, null, relations));
            serverMap.remove(model.getInstanceId().toLowerCase());
        }
        for (Map.Entry<String, CloudServer> entry : serverMap.entrySet()) {
            CloudServer server = entry.getValue();
            cloudServerRepository.remove(server.getId(), userId);
            // 删除资源表
            resourceRepository.remove(server.getId(), ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(),
                    userId);
            // cmdb：删除虚拟机
//            infos.add(CmdbInfoConvertor.getInfo(server, "delete", null));
            serverSgroupRepository.removeBySid(server.getId());
        }
    }

    private void updateServerKeyPair(CloudServer server, Map<String, Keypair> keyPairMap) throws Exception {
        String sshKeys = server.getSshKey();
        if (!StringUtils.isEmpty(sshKeys)) {
            List<String> keys = JSONArray.parseArray(sshKeys, String.class);
            for (String key : keys) {
                ServerKeypair serverKeypair = new ServerKeypair();
                Keypair keypair = keyPairMap.get(key.toLowerCase());
                if (null == keypair) {
                    continue;
                }
                serverKeypair.setKeypairId(keypair.getId());
                serverKeypair.setServerId(server.getId());
                serverKeyPairRepository.save(serverKeypair);
            }
        }
    }

    /**
     * 更新资源表相关信息
     *
     * @param server
     * @param vendor
     * @param userId
     * @throws Exception
     */
    private void updateResource(CloudServer server, CloudVendor vendor, String region, Long userId) {
        // 更新资源表
        Resource resource = resourceRepository.query(ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(),
                server.getId());
        List<String> ips = new ArrayList<>();
        if (!StringUtils.isEmpty(server.getPrivateIps()) && server.getPrivateIps().contains("[")) {
            ips.addAll(JSONArray.parseArray(server.getPrivateIps(), String.class));
        }
        if (!StringUtils.isEmpty(server.getPublicIps()) && server.getPublicIps().contains("[")) {
            ips.addAll(JSONArray.parseArray(server.getPublicIps(), String.class));
        }
        if (null != resource) {
            resource.setStatus(server.getStatus());
            resource.setPrivateIps(JSONObject.toJSONString(ips));
            resource.setRegionId(region);
            resource.setMenderId(userId);
            resource.setAccurated(false);
            resource.setAuthed(false);
            resourceRepository.update(resource);
            server.setResource(resource);
        } else {
            resource = new Resource(ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(), server.getId(),
                    null, server.getOsCategory(), vendor.getId());
            resource.preSave(server.getName(), server.getStatus(), userId, 0L, 0L);
            resource.setInventory(JSONObject.toJSONString(server));
            resource.setRegionId(region);
            resource.setPrivateIps(JSONObject.toJSONString(ips));
            resource.setOwnerId(userId);
            resource.setAccurated(false);
            resource.setAuthed(false);
            resourceRepository.save(resource);
            server.setResource(resource);
        }
    }

    /**
     * 更新虚拟机安全组
     *
     * @param serverId
     * @param securityGroupUuids
     * @param groupMap
     * @throws Exception
     */
    private void updateSGroup(Long serverId, String securityGroupUuids, Map<String, SecurityGroup> groupMap) {
        if (!StringUtils.isEmpty(securityGroupUuids)) {
            List<String> groupUuidList = JSONArray.parseArray(securityGroupUuids, String.class);
            for (String groupUuid : groupUuidList) {
                ServerSgroup serverSgroup = new ServerSgroup(serverId, groupMap.get(groupUuid.toLowerCase()).getId());
                serverSgroupRepository.save(serverSgroup);
            }
        }
    }

}
