package com.bocloud.ims.service.transportor;

import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.entity.enums.ResourceCategory;
import com.bocloud.cmp.model.*;
import com.bocloud.common.enums.ResourceCatalog;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.service.model.cmdb.CmdbInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 *
 * @ClassName: JdcloudTransportor.java
 * @Description: 京东云同步工具类
 *
 * @author: ymh
 * @date: 2021年3月15日 下午4:44:06
 */
@Component("jdcloudTransportor")
public class JdcloudTransportor implements Transportor {

    private static Logger logger = LoggerFactory.getLogger(JdcloudTransportor.class);

    @Autowired
    private ImageRepository imageRepository;
    @Autowired
    private FlavorRepository flavorRepository;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private ServerSgroupRepository serverSgroupRepository;
    @Autowired
    private VolumeRepository volumeRepository;
    @Autowired
    private SnapshotRepository snapshotRepository;
    @Autowired
    private ZoneRepository zoneRepository;
    @Autowired
    private VpcRepository vpcRepository;
    @Autowired
    private SubnetRepository subnetRepository;
    @Autowired
    private SecurityGroupRepository securityGroupRepository;
    @Autowired
    private SecurityGroupRuleRepository securityGroupRuleRepository;
    @Autowired
    private RouteTableRepository routeTableRepository;
    @Autowired
    private KeypairRepository keypairRepository;
    @Autowired
    private ServerKeypairRepository serverKeypairRepository;
    @Autowired
    private ElasticIpRepository elasticIpRepository;

    @Override
    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, "该平台下有虚拟机正在创建，请稍后进行同步操作");
                }
                String content = JSONObject.toJSONString(data);
                JdSyncModel model = JSONObject.parseObject(content, JdSyncModel.class);

                // 同步az
                logger.info("Starting sync az......");
                this.syncAz(model.getZoneModels(), vendor, userId, region);
                logger.info("end sync az......");

                // 同步镜像
                logger.info("Starting sync image......");
                this.syncImage(model.getImageModels(), vendor, userId, region);
                logger.info("End sync image......");
                // 同步虚拟机实例
                logger.info("Starting sync instance type......");
                this.syncInstanceType(model.getFlavorModels(), vendor.getId(), userId, region);
                logger.info("End sync instance type......");
                // 同步虚拟机
                logger.info("Starting sync server......");
                this.syncServer(model.getServerModels(), vendor, userId, region);
                logger.info("End sync server......");

                List<CloudServer> cloudServers =
                    cloudServerRepository.listByVendorId(vendor.getId(), region.getRegionId());
                Map<String, Long> serverMap = Maps.newHashMap();
                for (CloudServer cloudServer : cloudServers) {
                    serverMap.put(cloudServer.getInstanceId(), cloudServer.getId());
                }
                // 同步硬盘
                logger.info("Starting sync volume......");
                this.syncVolume(model.getVolumeModels(), region, vendor, userId, serverMap);
                logger.info("End sync volume......");

                List<Volume> volumes = volumeRepository.listByVendorId(vendor.getId());
                Map<String,
                    Long> volumeMap =
                        Optional.ofNullable(volumes)
                            .map(entityVolumes -> entityVolumes.stream()
                                .collect(Collectors.toMap(Volume::getVolumeUuid, Volume::getId)))
                            .orElse(new HashMap<>(8));

                // 同步快照
                logger.info("Starting sync snapshot......");
                this.syncSnapshot(model.getSnapshotModels(), region, vendor, userId, volumeMap);
                logger.info("End sync snapshot......");

                // 同步vpc
                logger.info("Starting sync vpc......");
                this.syncVpc(model.getVpcModels(), vendor.getId(), userId, region.getRegionId());
                logger.info("End sync vpc......");

                Map<String, Long> vpcMap = new HashMap<>(8);
                List<Vpc> vpcList = vpcRepository.list(vendor.getId(), region.getRegionId());
                if (!ListTool.isEmpty(vpcList)) {
                    vpcMap = vpcList.stream().collect(Collectors.toMap(Vpc::getVpcId, Vpc::getId));
                }

                List<Subnet> subnets = subnetRepository.listByVid(vendor.getId());
                Map<String,
                    Subnet> subnetMap = Optional.ofNullable(subnets)
                        .map(entityVolumes -> entityVolumes.stream()
                            .collect(Collectors.toMap(Subnet::getSubnetUuid, Subnet -> Subnet)))
                        .orElse(new HashMap<>(8));

                // 同步路由表
                logger.info("Starting sync route table......");
                this.syncRouteTable(model.getRouteTableModels(), vendor.getId(), userId, region.getRegionId(), vpcMap,
                    subnetMap);
                logger.info("End sync route table......");

                // 同步安全组
                logger.info("Starting sync NetworkSecurityGroups......");
                this.syncNetworkSecurityGroups(model.getSecurityGroupModels(), vendor.getId(), userId,
                    region.getRegionId(), vpcMap);
                logger.info("End sync NetworkSecurityGroups......");

                // 同步秘钥
                logger.info("Starting sync Keypairs......");
                this.syncKeypairs(model.getKeypairModels(), vendor.getId(), userId, region.getRegionId());
                logger.info("End sync Keypairs......");

                // 同步弹性公网IP
                logger.info("Starting sync elasticip......");
                this.syncElastip(model.getElasticIpModels(), vendor.getId(), userId, region.getRegionId(), serverMap);
                logger.info("End sync elasticip......");

            }
            return new BocloudResult(true, "云平台【" + vendor.getName() + "】平台数据同步成功");
        } catch (Exception e) {
            logger.error("Get error message:", e);
            return new BocloudResult(false, "云平台【" + vendor.getName() + "】平台数据同步失败:" + e.getMessage());
        }
    }

    /**
     * @Author: lxy
     * @Description: 同步秘钥
     * @Date 2021/6/18 14:05
     * @Param keypairModels
     * @param vendorId
     * @param userId
     * @param regionId
     * @return void
     * @throws:
     **/
    private void syncKeypairs(List<KeypairModel> keypairModels, Long vendorId, Long userId, String regionId)
        throws Exception {
        List<Keypair> keypairs = keypairRepository.listByVid(vendorId, regionId);
        if (!ListTool.isEmpty(keypairs) && ListTool.isEmpty(keypairModels)) {
            for (Keypair keypair : keypairs) {
                serverKeypairRepository.removeBySgid(keypair.getId());
            }
            keypairRepository.removeByVid(vendorId, userId, regionId);
        }
        Map<String, Keypair> keypairMap = Maps.newHashMap();
        for (Keypair keypair : keypairs) {
            keypairMap.put(keypair.getName(), keypair);
        }
        for (KeypairModel model : keypairModels) {
            Keypair keypair = new Keypair();
            if (keypairMap.containsKey(model.getName())) {
                keypair = keypairMap.get(model.getName());
                BeanUtils.copyProperties(model, keypair);
                model.setGmtCreate(keypair.getGmtCreate());
                model.setUserUuid(keypair.getUserUuid());
                keypair.setMenderId(userId);
                keypair.setGmtModify(new Date());
                keypairRepository.update(keypair);
                keypairMap.remove(keypair.getName());
                // 处理虚拟机对应私钥
                saveServerKeypair(model.getInstanceIds(), keypair.getId());
                continue;
            }
            BeanUtils.copyProperties(model, keypair);
            keypair.setCreatorId(userId);
            keypair.setGmtCreate(model.getGmtCreate());
            keypair.setVendorId(vendorId);
            keypair.setTenantId(0L);
            keypair.setProjectId(0L);
            keypairRepository.save(keypair);
            // 处理虚拟机对应私钥
            saveServerKeypair(model.getInstanceIds(), keypair.getId());
        }
        for (Map.Entry<String, Keypair> entry : keypairMap.entrySet()) {
            keypairRepository.remove(entry.getValue().getId(), userId);
        }
    }

    /**
     * @Author: lxy
     * @Description: 虚拟机对应私钥
     * @Date 2021/6/18 15:04
     * @Param instanceIds
     * @param keypairId
     * @return void
     * @throws:
     **/
    private void saveServerKeypair(List<String> instanceIds, Long keypairId) {
        if (ListTool.isEmpty(instanceIds)) {
            return;
        }
        List<ServerKeypair> serverKeypairs = new ArrayList<>();
        for (String instanceId : instanceIds) {
            ServerKeypair serverKeypair = new ServerKeypair();
            CloudServer cloudServer = cloudServerRepository.get(instanceId);
            serverKeypair.setKeypairId(keypairId);
            serverKeypair.setServerId(cloudServer.getId());
            serverKeypairs.add(serverKeypair);
        }
        serverKeypairRepository.batchSave(serverKeypairs, serverKeypairs.size() + 1);
    }

    /**
     * @Author: lxy
     * @Description: 同步安全组
     * @Date 2021/6/17 13:51
     * @Param securityGroupModels
     * @param vendorId
     * @param userId
     * @param regionId
     * @return void
     * @throws:
     **/
    private void syncNetworkSecurityGroups(List<SecurityGroupModel> securityGroupModels, Long vendorId, Long userId,
        String regionId, Map<String, Long> vpcMap) throws Exception {
        List<SecurityGroup> securityGroups = securityGroupRepository.listByVendorId(vendorId, regionId, null);
        if (!ListTool.isEmpty(securityGroups) && ListTool.isEmpty(securityGroupModels)) {
            List<Long> groupIds =
                securityGroups.stream().map(securityGroup -> securityGroup.getId()).collect(Collectors.toList());
            // 删除安全组规则
            securityGroupRuleRepository.deleteByVid(vendorId, userId, groupIds);
            // 删除安全组
            securityGroupRepository.deleteByVid(vendorId, regionId, userId);
            return;
        }

        Map<String, SecurityGroup> securityGroupMap = Maps.newHashMap();
        for (SecurityGroup securityGroup : securityGroups) {
            securityGroupMap.put(securityGroup.getGroupUuid(), securityGroup);
        }
        for (SecurityGroupModel model : securityGroupModels) {
            SecurityGroup securityGroup = new SecurityGroup();
            if (securityGroupMap.containsKey(model.getGroupUuid())) {
                securityGroup = securityGroupMap.get(model.getGroupUuid());
                BeanUtils.copyProperties(model, securityGroup);
                securityGroup.preSave(userId, userId, vendorId, 0L, 0L);
                securityGroup.setMenderId(userId);
                securityGroup.setRegionId(regionId);
                securityGroup.setVpcId(vpcMap.get(securityGroup.getVpcUuid()));
                securityGroupRepository.update(securityGroup);
                // 保存vpc下的子网
                syncSecurityGroupRule(model.getModels(), vendorId, userId, securityGroup.getId());
                securityGroupMap.remove(model.getGroupUuid());
                continue;
            }
            BeanUtils.copyProperties(model, securityGroup);
            securityGroup.preSave(userId, userId, vendorId, 0L, 0L);
            securityGroup.setRegionId(regionId);
            securityGroup.setVpcId(vpcMap.get(securityGroup.getVpcUuid()));
            securityGroupRepository.save(securityGroup);
            // 保存vpc下的子网
            syncSecurityGroupRule(model.getModels(), vendorId, userId, securityGroup.getId());
            securityGroupMap.remove(model.getGroupUuid());
        }
        for (Entry<String, SecurityGroup> entry : securityGroupMap.entrySet()) {
            securityGroupRepository.delete(entry.getValue().getId(), userId);
        }

    }

    /**
     * @Author: lxy
     * @Description: 安全组下规则
     * @Date 2021/6/17 14:40
     * @Param models
     * @param vendorId
     * @param userId
     * @param groupId
     * @return void
     * @throws:
     **/
    private void syncSecurityGroupRule(List<SecurityGroupRuleModel> models, Long vendorId, Long userId, Long groupId)
        throws Exception {
        if (ListTool.isEmpty(models)) {
            List<Long> groupIds = new ArrayList<>();
            groupIds.add(groupId);
            securityGroupRuleRepository.deleteByVid(vendorId, userId, groupIds);
            return;
        }
        // 处理安全组具有的规则信息
        List<SecurityGroupRule> rules = securityGroupRuleRepository.listBySgId(groupId);
        Map<String, SecurityGroupRule> ruleMap = Maps.newHashMap();
        for (SecurityGroupRule rule : rules) {
            if (ruleMap.containsKey(rule.getRuleUuid())) {
                securityGroupRuleRepository.remove(rule.getId(), userId);
            } else {
                ruleMap.put(rule.getRuleUuid(), rule);
            }
        }

        for (SecurityGroupRuleModel model : models) {
            if (ruleMap.containsKey(model.getRuleUuid())) {
                SecurityGroupRule securityGroupRule = ruleMap.get(model.getRuleUuid());
                BeanUtils.copyProperties(model, securityGroupRule);
                securityGroupRule.setGmtModify(new Date());
                securityGroupRule.setMenderId(userId);
                securityGroupRuleRepository.update(securityGroupRule);
                ruleMap.remove(model.getRuleUuid());
                continue;
            }
            // 保存新的安全组规则
            SecurityGroupRule rule = JSONObject.parseObject(JSONObject.toJSONString(model), SecurityGroupRule.class);
            rule.preSave(userId, userId, vendorId, groupId, 0L, 0L);
            securityGroupRuleRepository.save(rule);
            ruleMap.remove(model.getRuleUuid());
        }
        // 删除不存在的安全组规则
        for (Entry<String, SecurityGroupRule> entry : ruleMap.entrySet()) {
            securityGroupRuleRepository.remove(entry.getValue().getId(), userId);
        }
    }

    /**
     * 同步vpc专用网络
     *
     * @param models
     * @param vendorId
     * @param userId
     * @throws Exception
     */
    private void syncVpc(List<VpcModel> models, Long vendorId, Long userId, String region) throws Exception {
        if (ListTool.isEmpty(models)) {
            vpcRepository.deleteByVid(vendorId, region, userId);
            return;
        }
        List<Vpc> vpcs = vpcRepository.list(vendorId, region);
        Map<String, Vpc> vpcMap = Maps.newHashMap();
        for (Vpc vpc : vpcs) {
            vpcMap.put(vpc.getVpcId(), vpc);
        }
        for (VpcModel model : models) {
            Vpc vpc = new Vpc();
            if (vpcMap.containsKey(model.getVpcId())) {
                vpc = vpcMap.get(model.getVpcId());
                BeanUtils.copyProperties(model, vpc);
                vpc.setMenderId(userId);
                vpc.setRegionId(region);
                vpcRepository.update(vpc);
                // 保存vpc下的子网
                syncSubnet(model.getSubnetModels(), vendorId, userId, region, vpc.getId());
                vpcMap.remove(model.getVpcId());
                continue;
            }
            BeanUtils.copyProperties(model, vpc);
            vpc.setCreatorId(userId);
            vpc.setVendorId(vendorId);
            vpc.setTenantId(0L);
            vpc.setProjectId(0L);
            vpc.setRegionId(region);
            vpcRepository.save(vpc);
            // 保存vpc下的子网
            syncSubnet(model.getSubnetModels(), vendorId, userId, region, vpc.getId());
            vpcMap.remove(model.getVpcId());
        }
        for (Entry<String, Vpc> entry : vpcMap.entrySet()) {
            vpcRepository.delete(entry.getValue().getId(), userId);
        }
    }

    /**
     * 同步路由表
     *
     * @param models
     * @param vendorId
     * @param userId
     * @throws Exception
     */
    private void syncRouteTable(List<RouteTableModel> models, Long vendorId, Long userId, String region,
        Map<String, Long> vpcMap, Map<String, Subnet> subnetMap) throws Exception {
        if (ListTool.isEmpty(models)) {
            routeTableRepository.removeByVid(vendorId, region, userId);
            return;
        }
        List<RouteTable> routeTables = routeTableRepository.listByVid(vendorId, region);
        Map<String, RouteTable> routeTableMap = Maps.newHashMap();
        for (RouteTable table : routeTables) {
            routeTableMap.put(table.getUuid(), table);
        }
        for (RouteTableModel model : models) {
            RouteTable table = new RouteTable();
            if (routeTableMap.containsKey(model.getUuid())) {
                table = routeTableMap.get(model.getUuid());
                BeanUtils.copyProperties(model, table);
                table.setMenderId(userId);
                table.setRegionId(region);
                if (!StringUtils.isEmpty(model.getVpcUuid())) {
                    table.setVpcId(vpcMap.get(model.getVpcUuid()));
                }
                routeTableRepository.update(table);
                // 同步子网和路由表的关系
                syncRouteTableSubnetRelation(model.getSubnetUuids(), table.getId(), subnetMap);
                routeTableMap.remove(model.getUuid());
                continue;
            }
            BeanUtils.copyProperties(model, table);
            table.setCreatorId(userId);
            table.setVendorId(vendorId);
            table.setRegionId(region);
            if (!StringUtils.isEmpty(model.getVpcUuid())) {
                table.setVpcId(vpcMap.get(model.getVpcUuid()));
            }
            routeTableRepository.save(table);
            // 同步子网和路由表的关系
            syncRouteTableSubnetRelation(model.getSubnetUuids(), table.getId(), subnetMap);
            routeTableMap.remove(model.getUuid());
        }
        for (Entry<String, RouteTable> entry : routeTableMap.entrySet()) {
            routeTableRepository.remove(entry.getValue().getId(), userId);
        }
    }

    /**
     * 同步子网和路由表的关系
     *
     * @param subnetUuids
     * @throws Exception
     */
    private void syncRouteTableSubnetRelation(List<String> subnetUuids, Long routeTable, Map<String, Subnet> subnetMap)
        throws Exception {
        if (subnetUuids == null) {
            return;
        }
        if (subnetUuids.isEmpty()) {
            List<Subnet> subnets = subnetRepository.listByRouterId(routeTable);
            for (Subnet subnet : subnets) {
                subnet.setRouterTableId(null);
                subnetRepository.update(subnet);
            }
        }

        for (String subnetUuid : subnetUuids) {
            if (subnetMap.containsKey(subnetUuid)) {
                Subnet subnet = subnetMap.get(subnetUuid);
                subnet.setRouterTableId(routeTable);
                subnetRepository.update(subnet);
            }
        }
    }

    private void syncSubnet(List<SubnetModel> models, Long vendorId, Long userId, String region, Long vpcId)
        throws Exception {
        if (ListTool.isEmpty(models)) {
            subnetRepository.removeByVpcId(vendorId, region, userId);
            return;
        }
        List<Subnet> subnets = subnetRepository.listByVpcId(vendorId, vpcId);
        Map<String, Subnet> subnetMap = Maps.newHashMap();
        for (Subnet subnet : subnets) {
            subnetMap.put(subnet.getSubnetUuid(), subnet);
        }
        Subnet subnet = null;
        for (SubnetModel subnetModel : models) {
            subnet = new Subnet();
            if (subnetMap.containsKey(subnetModel.getSubnetUuid())) {
                BeanUtils.copyProperties(subnetModel, subnet);
                subnet.setSubnetUuid(subnetModel.getSubnetUuid());
                subnet.setNetworkId(vpcId);
                subnet.setVpcId(vpcId);
                subnet.setMenderId(userId);
                subnet.setGmtModify(new Date());
                subnet.setVendorId(vendorId);
                subnet.setRegionId(region);
                subnetRepository.update(subnet);
                subnetMap.remove(subnet.getSubnetUuid());
                continue;
            }
            BeanUtils.copyProperties(subnetModel, subnet);
            subnet.setSubnetUuid(subnetModel.getSubnetUuid());
            subnet.setNetworkId(vpcId);
            subnet.setVpcId(vpcId);
            subnet.setCreatorId(userId);
            subnet.setGmtCreate(subnetModel.getGmtCreate());
            subnet.setVendorId(vendorId);
            subnet.setRegionId(region);
            subnetRepository.save(subnet);
            subnetMap.remove(subnet.getSubnetUuid());

        }

        for (Entry<String, Subnet> entry : subnetMap.entrySet()) {
            subnetRepository.remove(entry.getValue().getId(), userId);
        }
    }

    private void syncAz(List<ZoneModel> models, CloudVendor vendor, Long userId, Region region) throws Exception {
        zoneRepository.deleteByRegionId(region.getRegionId(), vendor.getId());
        if (null != models && models.size() > 0) {
            Zone zone = null;
            List<Zone> zoneList = Lists.newArrayList();
            for (ZoneModel model : models) {
                zone = new Zone();
                BeanUtils.copyProperties(model, zone);
                zone.setVendorId(vendor.getId());
                zoneList.add(zone);
            }
            if (zoneList.size() > 0) {
                zoneRepository.batchSave(zoneList);
            }
        }
    }

    /**
     * 同步硬盘数据
     *
     * @param models
     * @param vendor
     * @param userId
     * @throws Exception
     */
    private void syncVolume(List<VolumeModel> models, Region region, CloudVendor vendor, Long userId,
        Map<String, Long> serverMap) throws Exception {
        // 删除 脏数据
        volumeRepository.deleteRegionNull(vendor.getId());
        if (ListTool.isEmpty(models)) {
            volumeRepository.removeByVid(vendor.getId(), region.getRegionId(), userId);
            return;
        }
        List<Volume> volumes = volumeRepository.listByVendorId(vendor.getId(), region.getRegionId());
        Map<String, Volume> volumeMap = Maps.newHashMap();
        for (Volume volume : volumes) {
            volumeMap.put(volume.getVolumeUuid(), volume);
        }
        for (VolumeModel model : models) {
            Volume volume = new Volume();
            if (volumeMap.containsKey(model.getVolumeUuid())) {
                volume = volumeMap.get(model.getVolumeUuid());
                BeanUtils.copyProperties(model, volume);
                volume.setMenderId(userId);
                volume.setGmtModify(new Date());
                volume.setRegionId(region.getRegionId());
                volume.setVendorType(vendor.getType());
                if (!StringUtils.isEmpty(model.getInstanceId())) {
                    volume.setServerId(serverMap.get(model.getInstanceId()));
                }
                volumeRepository.update(volume);
                volumeMap.remove(volume.getVolumeUuid());
                continue;
            }
            BeanUtils.copyProperties(model, volume);
            volume.setCreatorId(userId);
            volume.setGmtCreate(new Date());
            volume.setVendorId(vendor.getId());
            volume.setRegionId(region.getRegionId());
            volume.setVendorType(vendor.getType());
            volume.setTenantId(0L);
            if (!StringUtils.isEmpty(model.getInstanceId())) {
                volume.setServerId(serverMap.get(model.getInstanceId()));
            }
            volumeRepository.save(volume);
            volumeMap.remove(volume.getVolumeUuid());
        }
        for (Entry<String, Volume> entry : volumeMap.entrySet()) {
            volumeRepository.remove(entry.getValue().getId(), userId);
        }
    }

    /**
     * 同步快照数据
     *
     * @param models
     * @param vendor
     * @param userId
     * @throws Exception
     */
    private void syncSnapshot(List<SnapshotModel> models, Region region, CloudVendor vendor, Long userId,
        Map<String, Long> volumeMap) throws Exception {
        if (ListTool.isEmpty(models)) {
            snapshotRepository.removeByVid(vendor.getId(), region.getRegionId(), userId);
            return;
        }
        List<Snapshot> snapshots = snapshotRepository.listByVid(vendor.getId());
        Map<String, Snapshot> snapshotMap = Maps.newHashMap();
        for (Snapshot snapshot : snapshots) {
            snapshotMap.put(snapshot.getSnapshotUuid(), snapshot);
        }
        for (SnapshotModel model : models) {
            Snapshot snapshot = new Snapshot();
            if (snapshotMap.containsKey(model.getSnapshotUuid())) {
                snapshot = snapshotMap.get(model.getSnapshotUuid());
                BeanUtils.copyProperties(model, snapshots);
                snapshot.setMenderId(userId);
                snapshot.setGmtModify(new Date());
                snapshot.setRegionId(region.getRegionId());
                snapshot.setVendorType(vendor.getType());
                if (!StringUtils.isEmpty(model.getVolumeUuid())) {
                    snapshot.setVolumeId(volumeMap.get(model.getVolumeUuid()));
                }
                snapshotRepository.update(snapshot);
                snapshotMap.remove(snapshot.getSnapshotUuid());
                continue;
            }
            BeanUtils.copyProperties(model, snapshot);
            snapshot.setCreatorId(userId);
            snapshot.setGmtCreate(model.getCreateTime());
            snapshot.setVendorId(vendor.getId());
            snapshot.setRegionId(region.getRegionId());
            snapshot.setVendorType(vendor.getType());
            snapshot.setTenantId(0L);
            if (!StringUtils.isEmpty(model.getVolumeUuid())) {
                snapshot.setVolumeId(volumeMap.get(model.getVolumeUuid()));
            }
            snapshotRepository.save(snapshot);
            snapshotMap.remove(snapshot.getSnapshotUuid());
        }
        for (Entry<String, Snapshot> entry : snapshotMap.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, Region region) throws Exception {
        if (ListTool.isEmpty(models)) {
            imageRepository.removeByVid(vendor.getId(), region.getRegionId(), userId);
            return;
        }
        List<Image> images = imageRepository.listByVendorId(vendor.getId(), region.getRegionId());
        Map<String, Image> imageMap = Maps.newHashMap();
        for (Image image : images) {
            imageMap.put(image.getImageUuid(), image);
        }
        for (ImageModel model : models) {
            Image image = new Image();
            if (imageMap.containsKey(model.getImageUuid())) {
                image = imageMap.get(model.getImageUuid());
                BeanUtils.copyProperties(model, image);
                image.setMenderId(userId);
                image.setGmtModify(new Date());
                image.setRegionId(region.getRegionId());
                image.setVendorType(vendor.getType());
                imageRepository.update(image);
                imageMap.remove(image.getImageUuid());
                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.getRegionId());
            image.setCatalog("VM");
            imageRepository.save(image);
            imageMap.remove(image.getImageUuid());
        }
        for (Entry<String, Image> entry : imageMap.entrySet()) {
            imageRepository.remove(entry.getValue().getId(), userId);
        }
    }

    /**
     * 同步虚拟机实例
     *
     * @param models
     * @param vendorId
     * @param region
     * @param userId
     * @throws Exception
     */
    private void syncInstanceType(List<FlavorModel> models, Long vendorId, Long userId, Region region)
        throws Exception {
        if (ListTool.isEmpty(models)) {
            flavorRepository.removeByVid(vendorId, region.getRegionId());
            return;
        }
        List<Flavor> flavors = flavorRepository.listByVendorId(vendorId, region.getRegionId());
        Map<String, Flavor> flavorMap = Maps.newHashMap();
        for (Flavor flavor : flavors) {
            flavorMap.put(flavor.getName(), flavor);
        }
        for (FlavorModel model : models) {
            Flavor flavor = new Flavor();
            if (flavorMap.containsKey(model.getName())) {
                flavor = flavorMap.get(model.getName());
                BeanUtils.copyProperties(model, flavor);
                flavorRepository.update(flavor);
                flavorMap.remove(model.getName());
                continue;
            }
            BeanUtils.copyProperties(model, flavor);
            flavor.setVendorId(vendorId);
            flavorRepository.save(flavor);
            flavorMap.remove(flavor.getName());
        }
        for (Entry<String, Flavor> entry : flavorMap.entrySet()) {
            flavorRepository.delete(entry.getValue().getId());
        }
    }

    /**
     * 同步虚拟机
     *
     * @param models
     * @param vendor
     * @param userId
     * @throws Exception
     */
    private void syncServer(List<ServerModel> models, CloudVendor vendor, Long userId, Region region) throws Exception {
        if (ListTool.isEmpty(models)) {
            cloudServerRepository.removeByVid(vendor.getId(), region.getRegionId(), userId);
            return;
        }
        List<CloudServer> servers = cloudServerRepository.listByVid(vendor.getId(), region.getRegionId());
        Map<String, CloudServer> serverMap = Maps.newHashMap();
        for (CloudServer server : servers) {
            serverMap.put(server.getInstanceId(), server);
        }
        for (ServerModel model : models) {
            CloudServer server = new CloudServer();
            if (serverMap.containsKey(model.getInstanceId())) {
                server = serverMap.get(model.getInstanceId());

                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.setRegionId(region.getRegionId());
                server.setVendorType(vendor.getType());
                server.setIsTemplate(false);
                Flavor flavor = flavorRepository.getByName(model.getInstanceType(), vendor.getId());
                if (null != flavor) {
                    server.setCpu(flavor.getCpu());
                    server.setMemory(flavor.getMemory());
                }
                Image image = imageRepository.getByImageUuid(server.getImageUuid());
                if (null != image) {
                    server.setOsCategory(image.getOsCategory());
                    server.setOsName(image.getOsName());
                    server.setOsVersion(image.getOsVersion());
                }
                cloudServerRepository.update(server);
                // 更新资源表
                updateResource(server, vendor, userId);
                serverMap.remove(model.getInstanceId());
                continue;
            }
            BeanUtils.copyProperties(model, server);
            server.setCreatorId(userId);
            server.setGmtCreate(new Date());
            server.setVendorId(vendor.getId());
            server.setVendorType(vendor.getType());
            server.setTenantId(0L);
            server.setRegionId(region.getRegionId());
            server.setIsTemplate(false);
            server.setRecycle(false);
            Flavor flavor = flavorRepository.getByName(model.getInstanceType(), vendor.getId());
            if (null != flavor) {
                server.setCpu(flavor.getCpu());
                server.setMemory(flavor.getMemory());
            }
            cloudServerRepository.save(server);
            // 更新资源表
            updateResource(server, vendor, userId);
            serverMap.remove(model.getInstanceId());
        }
        for (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);
            serverSgroupRepository.removeBySid(server.getId());
        }
    }

    /**
     * 更新资源表相关信息
     *
     * @param server
     * @param vendor
     * @param userId
     * @throws Exception
     */
    private void updateResource(CloudServer server, CloudVendor vendor, Long userId) throws Exception {
        // 更新资源表
        Resource resource =
            resourceRepository.query(ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(), server.getId());
        if (null != resource) {
            resource.setStatus(server.getStatus());
            List<String> ips = Lists.newArrayList();
            ips.add(server.getPrivateIps());
            resource.setPrivateIps(JSONObject.toJSONString(ips));
            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));
            List<String> ips = Lists.newArrayList();
            ips.add(server.getPrivateIps());
            resource.setPrivateIps(JSONObject.toJSONString(ips));
            resource.setOwnerId(userId);
            resource.setAccurated(false);
            resource.setAuthed(false);
            resourceRepository.save(resource);
            server.setResource(resource);
        }
    }

    /**
     * 同步弹性公网IP数据
     *
     * @param models
     * @param vendorId
     * @param userId
     * @throws Exception
     */
    private void syncElastip(List<ElasticIpModel> models, Long vendorId, Long userId, String region,
        Map<String, Long> serverMap) throws Exception {
        if (ListTool.isEmpty(models)) {
            elasticIpRepository.removeByVid(vendorId, userId, region);
            return;
        }
        List<ElasticIp> elasticIps = elasticIpRepository.listByVid(vendorId, region);
        Map<String, ElasticIp> elasticIpMap = Maps.newHashMap();
        for (ElasticIp elasticIp : elasticIps) {
            elasticIpMap.put(elasticIp.getElasticIpUuid(), elasticIp);
        }
        for (ElasticIpModel model : models) {
            ElasticIp elasticIp = new ElasticIp();
            if (elasticIpMap.containsKey(model.getElasticIpUuid())) {
                elasticIp = elasticIpMap.get(model.getElasticIpUuid());
                BeanUtils.copyProperties(model, elasticIp);
                elasticIp.setMenderId(userId);
                elasticIp.setGmtModify(new Date());
                elasticIp.setRegionId(region);
                elasticIp.setInstanceId(model.getInstanceId());
                elasticIpRepository.update(elasticIp);
                elasticIpMap.remove(elasticIp.getElasticIpUuid());
                continue;
            }
            BeanUtils.copyProperties(model, elasticIp);
            elasticIp.setCreatorId(userId);
            elasticIp.setGmtCreate(new Date());
            elasticIp.setVendorId(vendorId);
            elasticIp.setRegionId(region);
            elasticIp.setTenantId(0L);
            elasticIpRepository.save(elasticIp);
            elasticIpMap.remove(elasticIp.getElasticIpUuid());
        }
        for (Entry<String, ElasticIp> entry : elasticIpMap.entrySet()) {
            elasticIpRepository.remove(entry.getValue().getId(), userId);
        }
    }

}
