package com.bocloud.ims.service.transportor;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import org.apache.commons.lang.StringUtils;
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.stereotype.Component;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.entity.enums.ModuleCode;
import com.bocloud.cmp.entity.enums.ResourceCategory;
import com.bocloud.cmp.model.ClusterModel;
import com.bocloud.cmp.model.FlavorModel;
import com.bocloud.cmp.model.FloatingIpModel;
import com.bocloud.cmp.model.ImageModel;
import com.bocloud.cmp.model.KeypairModel;
import com.bocloud.cmp.model.NetworkCardModel;
import com.bocloud.cmp.model.RegionModel;
import com.bocloud.cmp.model.ResourceGroupModel;
import com.bocloud.cmp.model.SecurityGroupModel;
import com.bocloud.cmp.model.SecurityGroupRuleModel;
import com.bocloud.cmp.model.ServerModel;
import com.bocloud.cmp.model.SubnetModel;
import com.bocloud.cmp.model.TianyiSyncModel;
import com.bocloud.cmp.model.VolumeModel;
import com.bocloud.cmp.model.VpcModel;
import com.bocloud.cmp.model.ZoneModel;
import com.bocloud.common.enums.ResourceCatalog;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.utils.IDFactory;
import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.entity.resource.CloudServer;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.Cluster;
import com.bocloud.ims.entity.resource.Flavor;
import com.bocloud.ims.entity.resource.FloatingIp;
import com.bocloud.ims.entity.resource.Image;
import com.bocloud.ims.entity.resource.Keypair;
import com.bocloud.ims.entity.resource.NetworkCard;
import com.bocloud.ims.entity.resource.Region;
import com.bocloud.ims.entity.resource.Resource;
import com.bocloud.ims.entity.resource.ResourceGroup;
import com.bocloud.ims.entity.resource.SecurityGroup;
import com.bocloud.ims.entity.resource.SecurityGroupRule;
import com.bocloud.ims.entity.resource.ServerKeypair;
import com.bocloud.ims.entity.resource.ServerSgroup;
import com.bocloud.ims.entity.resource.Subnet;
import com.bocloud.ims.entity.resource.Volume;
import com.bocloud.ims.entity.resource.Vpc;
import com.bocloud.ims.entity.resource.Zone;
import com.bocloud.ims.repository.resource.CloudServerRepository;
import com.bocloud.ims.repository.resource.ClusterRepository;
import com.bocloud.ims.repository.resource.FlavorRepository;
import com.bocloud.ims.repository.resource.FloatingIpRepository;
import com.bocloud.ims.repository.resource.ImageRepository;
import com.bocloud.ims.repository.resource.KeypairRepository;
import com.bocloud.ims.repository.resource.NetworkCardRepository;
import com.bocloud.ims.repository.resource.PoolGroupRepository;
import com.bocloud.ims.repository.resource.RegionRepository;
import com.bocloud.ims.repository.resource.ResourceGroupRepository;
import com.bocloud.ims.repository.resource.ResourceRepository;
import com.bocloud.ims.repository.resource.SecurityGroupRepository;
import com.bocloud.ims.repository.resource.SecurityGroupRuleRepository;
import com.bocloud.ims.repository.resource.ServerKeypairRepository;
import com.bocloud.ims.repository.resource.ServerLabelRepository;
import com.bocloud.ims.repository.resource.ServerSgroupRepository;
import com.bocloud.ims.repository.resource.SubnetRepository;
import com.bocloud.ims.repository.resource.VolumeRepository;
import com.bocloud.ims.repository.resource.VpcRepository;
import com.bocloud.ims.repository.resource.ZoneRepository;
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.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * @Author: Hu Wentao
 * @Date: 2020/10/23 14:46
 * @Description: 天翼云同步转换
 **/
@Component("tianyiTransportor")
public class TianyiTransportor implements Transportor {

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

	@Autowired
	private ImageRepository imageRepository;
	@Autowired
	private FlavorRepository flavorRepository;
	@Autowired
	private VolumeRepository volumeRepository;
	@Autowired
	private SecurityGroupRepository securityGroupRepository;
	@Autowired
	private ServerSgroupRepository serverSgroupRepository;
	@Autowired
	private CloudServerRepository cloudServerRepository;
	@Autowired
	private RegionRepository regionRepository;
	@Autowired
	private ZoneRepository zoneRepository;
	@Autowired
	private ResourceRepository resourceRepository;
	@Autowired
	private VpcRepository vpcRepository;
	@Autowired
	private ClusterRepository clusterRepository;
	@Autowired
	private ServerKeypairRepository serverKeyPairRepository;
	@Autowired
	private KeypairRepository keypairRepository;
	@Autowired
	private SecurityGroupRuleRepository securityGroupRuleRepository;
	@Autowired
	private PoolGroupRepository poolGroupRepository;
	@Autowired
	private SubnetRepository subnetRepository;
	@Autowired
	private ResourceGroupRepository resourceGroupRepository;
	@Autowired
	private FloatingIpRepository floatingIpRepository;
	@Autowired
	private NetworkCardRepository networkCardRepository;
	@Autowired
	private ServerLabelRepository serverLabelRepository;
	@Autowired
	private AmqpTemplate amqpTemplate;

	@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);
				TianyiSyncModel model = JSONObject.parseObject(content, TianyiSyncModel.class);

				// 同步集群
				logger.info("Starting sync cluster......");
				this.syncCluster(model.getClusterModels(), vendor, userId, region);
				logger.info("End sync cluster......");
				// 同步vpc
				logger.info("Starting sync vpc......");
				this.syncVpc(model.getVpcModels(), vendor.getId(), userId, region);
				logger.info("End sync vpc......");
				// 获取vpc信息
				Map<String, Vpc> vpcMap = Maps.newHashMap();
				List<Vpc> vpcList = vpcRepository.list(vendor.getId(), region.getRegionId());
				for (Vpc vpc : vpcList) {
					vpcMap.put(vpc.getVpcId(), vpc);
				}

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

				List<SecurityGroup> groups = securityGroupRepository.listByVendorId(vendor.getId(),
						region.getRegionId());
				Map<String, Long> groupMap = Maps.newHashMap();
				for (SecurityGroup group : groups) {
					groupMap.put(group.getName(), group.getId());
				}
				// 同步镜像
				logger.info("Starting sync image......");
				this.syncImage(model.getImageModels(), region, vendor, userId);
				logger.info("End sync image......");
				List<Image> imageList = imageRepository.listByVendorId(vendor.getId(), region.getRegionId());
				Map<String, Image> imageMap = Maps.newHashMap();
				for (Image image : imageList) {
					imageMap.put(image.getImageUuid(), image);
				}
				// 同步密钥
				logger.info("Starting sync keypair......");
				this.syncKeypair(model.getKeypairModels(), region.getRegionId(), vendor.getId(), userId);
				logger.info("End sync keypair...");
				List<Keypair> keyPairList = keypairRepository.listByVid(vendor.getId(), region.getRegionId());
				Map<String, Long> keyPairMap = new HashMap<>(8);
				for (Keypair keypair : keyPairList) {
					keyPairMap.put(keypair.getFingerprint(), keypair.getId());
				}

				// 同步浮动IP
				logger.info("Starting sync resourcegroups ......");
				this.syncFloatIps(model.getServerModels(), model.getFloatingIpModels(), vendor, userId, region);
				logger.info("End sync resourcegroups ......");
				// 同步虚拟机规格
				logger.info("Starting sync instance type......");
				this.syncInstanceType(model.getFlavorModels(), vendor.getId(), region);
				List<Flavor> flavors = flavorRepository.listByVendorId(vendor.getId(), region.getRegionId());
				Map<String, Flavor> flavorsMap = Maps.newHashMap();
				for (Flavor flavor : flavors) {
					flavorsMap.put(flavor.getFlavorUuid(), flavor);
				}
				logger.info("End sync instance type......");
				// 同步虚拟机
				logger.info("Starting sync server......");
				this.syncServer(model.getServerModels(), vendor, userId, groupMap, region, imageMap, keyPairMap,
						flavorsMap);
				logger.info("End sync server......");

				List<CloudServer> cloudServers = cloudServerRepository.listByVendorId(vendor.getId());
				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(), vendor, userId, serverMap, region);
				logger.info("End sync volume......");
				// 获取云硬盘信息
				Map<String, Long> volumeMap = Maps.newHashMap();
				List<Volume> volumes = volumeRepository.listByVendorId(vendor.getId());
				for (Volume volume : volumes) {
					volumeMap.put(volume.getVolumeUuid(), volume.getId());
				}
				// 同步域
				logger.info("Starting sync region and zone......");
				this.syncRegion(model.getRegionModels(), region, vendor, userId);
				logger.info("End sync region and zone......");
				// 同步交换机
				logger.info("Starting sync switch......");
				this.syncSubnets(model.getSubnetModels(), vendor.getId(), userId, region, vpcMap);
				logger.info("End sync switch......");

				// 同步资源组
				logger.info("Starting sync resourcegroups ......");
				this.syncResourceGroups(model.getResourceGroupModels(), vendor, userId, region);
				logger.info("End sync resourcegroups ......");
			}
			return new BocloudResult(true, "云平台【" + vendor.getName() + "】平台数据同步成功");
		} catch (Exception e) {
			logger.error("Get error message:", e);
			return new BocloudResult(false, "云平台【" + vendor.getName() + "】平台数据同步失败:" + e.getMessage());
		}
	}

	/**
	 * @author Hu Wentao
	 * @date 2020/10/29 10:31
	 * @Description: 修改浮动内网ip、ip绑定的虚拟机id
	 */
	private void syncFloatingIp(List<FloatingIp> floatingIps, Map<String, String> floatingIpMap) {
		if (ListTool.isEmpty(floatingIps)) {
			return;
		}
		for (FloatingIp floatingIp : floatingIps) {
			String instanceId = floatingIp.getInstanceId();
			if (!StringUtils.isEmpty(instanceId) && "BIND".equalsIgnoreCase(floatingIp.getStatus())) {
				CloudServer cloudServer = cloudServerRepository.getByInstanceId(instanceId, floatingIp.getVendorId());
				if (null != cloudServer && !StringUtils.isEmpty(cloudServer.getPrivateIps())) {
					List<String> ips = JSONObject.parseArray(cloudServer.getPrivateIps(), String.class);
					if (!ListTool.isEmpty(ips)) {
						floatingIp.setFixedIpAddress(ips.get(0));
						floatingIpRepository.update(floatingIp);
					}
				}
			}
			if (floatingIpMap.containsKey(floatingIp.getFloatingIpUuid())) {
				floatingIp.setInstanceId(floatingIpMap.get(floatingIp.getFloatingIpUuid()));
				floatingIpRepository.update(floatingIp);
			}
		}
	}

	private void syncFloatIps(List<ServerModel> serverModels, List<FloatingIpModel> floatingIpModels,
			CloudVendor vendor, Long userId, Region region) throws Exception {
		Long vendorId = vendor.getId();
		// 当浮动IP为空时，清空数据库
		if (ListTool.isEmpty(floatingIpModels)) {
			floatingIpRepository.removeByVid(vendorId, region.getRegionId(), userId);
			return;
		}
		List<FloatingIp> listByVid = floatingIpRepository.listByVid(vendorId, region.getRegionId());
		Map<String, FloatingIp> ipMap = Maps.newHashMap();
		for (FloatingIp ip : listByVid) {
			ipMap.put(ip.getFloatingIpUuid(), ip);
		}
		FloatingIp floating = null;
		Map<String, String> privateIpMap = new HashMap<>(8);
		for (ServerModel serverModel : serverModels) {
			List<String> ips = JSONArray.parseArray(serverModel.getPrivateIps(), String.class);
			for (String ip : ips) {
				privateIpMap.put(ip, serverModel.getInstanceId());
			}
		}
		for (FloatingIpModel model : floatingIpModels) {
			if (ipMap.containsKey(model.getFloatingIpUuid())) {
				floating = ipMap.get(model.getFloatingIpUuid());
				BeanUtils.copyProperties(model, floating);
				if (StringUtils.isEmpty(model.getInstanceId())) {
					floating.setInstanceId(null);
				}
				if ("BIND".equalsIgnoreCase(model.getStatus())) {
					String privateIpAddress = model.getPrivateIpAddress();
					if (privateIpMap.containsKey(privateIpAddress)) {
						floating.setInstanceId(privateIpMap.get(privateIpAddress));
					}
				}
				floating.setMenderId(userId);
				floating.setRegionId(region.getRegionId());
				floating.setGmtModify(new Date());
				floating.setCreatorId(userId);
				floating.setVendorId(vendorId);
				floatingIpRepository.update(floating);
				ipMap.remove(model.getFloatingIpUuid());
				continue;
			}
			floating = new FloatingIp();
			BeanUtils.copyProperties(model, floating);
			if (StringUtils.isEmpty(model.getInstanceId())) {
				floating.setInstanceId(null);
			}
			if ("BIND".equalsIgnoreCase(model.getStatus())) {
				String privateIpAddress = model.getPrivateIpAddress();
				if (privateIpMap.containsKey(privateIpAddress)) {
					floating.setInstanceId(privateIpMap.get(privateIpAddress));
				}
			}
			floating.setMenderId(userId);
			floating.setRegionId(region.getRegionId());
			floating.setGmtModify(new Date());
			floating.setTenantId(0L);
			floating.setProjectId(0L);
			floating.setCreatorId(userId);
			floating.setVendorId(vendorId);
			floatingIpRepository.save(floating);
		}
		for (Entry<String, FloatingIp> entry : ipMap.entrySet()) {
			floatingIpRepository.remove(entry.getValue().getId(), userId);
		}

	}

	private void syncResourceGroups(List<ResourceGroupModel> resourceGroupModels, CloudVendor vendor, Long userId,
			Region region) throws Exception {
		if (ListTool.isEmpty(resourceGroupModels)) {
			resourceGroupRepository.removeByVid(vendor.getId(), userId);
			return;
		}
		List<ResourceGroup> listResourceGroups = resourceGroupRepository.listByVendorId(vendor.getId());
		Map<String, ResourceGroup> resourceGroupMap = Maps.newHashMap();
		for (ResourceGroup resourceGroup : listResourceGroups) {
			resourceGroupMap.put(resourceGroup.getResourceGroupUuid(), resourceGroup);
		}
		for (ResourceGroupModel model : resourceGroupModels) {
			ResourceGroup resourceGroup = new ResourceGroup();
			String resourceGroupUuid = model.getResourceGroupUuid();
			if (resourceGroupMap.containsKey(resourceGroupUuid)) {
				resourceGroup = resourceGroupMap.get(resourceGroupUuid);
				BeanUtils.copyProperties(model, resourceGroup);
				resourceGroup.setMenderId(userId);
				resourceGroup.setGmtModify(new Date());
				resourceGroupRepository.update(resourceGroup);
				resourceGroupMap.remove(resourceGroupUuid);
				continue;
			}
			BeanUtils.copyProperties(model, resourceGroup);
			resourceGroup.setCreatorId(userId);
			resourceGroup.setGmtCreate(new Date());
			resourceGroup.setVendorId(vendor.getId());
			resourceGroup.setTenantId(0L);
			resourceGroup.setProjectId(0L);
			resourceGroupRepository.save(resourceGroup);
		}
		for (Entry<String, ResourceGroup> entry : resourceGroupMap.entrySet()) {
			resourceGroupRepository.remove(entry.getValue().getId(), userId);
		}

	}

	private void syncSubnets(List<SubnetModel> subnetModels, Long vendorId, Long userId, Region region,
			Map<String, Vpc> vpcMap) {
		if (ListTool.isEmpty(subnetModels)) {
			subnetRepository.removeByVid(vendorId, region.getRegionId(), userId);
			return;
		}
		List<Subnet> listByRegion = subnetRepository.listByRegion(vendorId, region.getRegionId());
		Map<String, Subnet> subnetMap = Maps.newHashMap();
		for (Subnet subnet : listByRegion) {
			subnetMap.put(subnet.getSubnetUuid(), subnet);
		}
		for (SubnetModel model : subnetModels) {
			Subnet subnet = new Subnet();
			if (subnetMap.containsKey(model.getSubnetUuid())) {
				subnet = subnetMap.get(model.getSubnetUuid());
				BeanUtils.copyProperties(model, subnet);
				subnet.setMenderId(userId);
				if (vpcMap.containsKey(subnet.getVpcUuid())) {
					subnet.setVpcId(vpcMap.get(subnet.getVpcUuid()).getId());
					subnet.setNetworkId(vpcMap.get(subnet.getVpcUuid()).getId());
				}
				subnet.setVendorId(vendorId);
				subnet.setRegionId(region.getRegionId());
				subnetRepository.update(subnet);
				subnetMap.remove(model.getSubnetUuid());
				continue;
			}
			BeanUtils.copyProperties(model, subnet);
			subnet.setCreatorId(userId);
			subnet.setVendorId(vendorId);
			if (vpcMap.containsKey(subnet.getVpcUuid())) {
				subnet.setVpcId(vpcMap.get(subnet.getVpcUuid()).getId());
				subnet.setNetworkId(vpcMap.get(subnet.getVpcUuid()).getId());
			}
			subnet.setRegionId(region.getRegionId());
			subnetRepository.save(subnet);
			vpcMap.remove(model.getSubnetUuid());
		}
		for (Entry<String, Subnet> entry : subnetMap.entrySet()) {
			subnetRepository.remove(entry.getValue().getId(), userId);
		}

	}

	/**
	 * 同步虚拟机
	 *
	 * @param models
	 * @param vendor
	 * @param userId
	 * @param groupMap
	 * @param
	 * @param flavorsMap
	 * @throws Exception
	 */
	private void syncServer(List<ServerModel> models, CloudVendor vendor, Long userId, Map<String, Long> groupMap,
			Region region, Map<String, Image> imageMap, Map<String, Long> keyPairMap, Map<String, Flavor> flavorsMap)
			throws Exception {
		// 删除 虚拟机 秘钥关联关系
		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) {
				serverSgroupRepository.removeBySid(server.getId());
				volumeRepository.detachVolumes(server.getId(), userId);
				serverLabelRepository.deleteByTarget(server.getId(), "VM");
			}
			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) {
			serverMap.put(server.getInstanceId(), server);
		}
		String vendorCode = ModuleCode.VENDOR.name() + "_PUBLIC";
		for (ServerModel model : models) {
			List<CmdbRelation> relations = Lists.newArrayList();
			relations.add(new CmdbRelation(vendorCode, null, ListUtils.getList(vendor.getGuid())));
			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.setGmtVmCreate(model.getGmtVmCreate());
				server.setRegionId(region.getRegionId());
				server.setVendorType(vendor.getType());
				server.setIsTemplate(false);
				List<String> securityGroups = model.getSecurityGroups();
				server.setNetworkUuid(server.getVpcUuid());
				server.setSubnetUuid(server.getVSwitchId());
				server.setVpcUuid(server.getVpcUuid());

				Image image = imageMap.get(server.getImageUuid());
				if (image != null && !"".equals(image)) {
					server.setOsCategory(image.getOsCategory());
					server.setOsName(image.getOsName());
					server.setOsVersion(image.getOsVersion());
				}
				Flavor flavor = flavorsMap.get(server.getFlavorUuid());
				if (null != flavor) {
					server.setCpu(flavor.getCpu());
					server.setMemory(flavor.getMemory());
				}

				cloudServerRepository.update(server);
				this.updateServerKeyPair(server, keyPairMap);
				// 更新资源表
				updateResource(server, vendor, region.getRegionId(), userId);
				// 更新虚拟机绑定的安全组
				serverSgroupRepository.removeBySid(server.getId());
				if (!ListTool.isEmpty(securityGroups)) {
					updateSgroup(server.getId(), securityGroups, groupMap);
				}
				serverMap.remove(model.getInstanceId());
				continue;
			}
			BeanUtils.copyProperties(model, server);
			List<String> securityGroups = model.getSecurityGroups();
			server.setCreatorId(userId);
			server.setGmtCreate(new Date());
			server.setVendorId(vendor.getId());
			server.setVendorType(vendor.getType());
			server.setTenantId(0L);
			server.setProjectId(0L);
			server.setRegionId(region.getRegionId());
			server.setIsTemplate(false);
			server.setRecycle(false);
			server.setNetworkUuid(server.getVpcUuid());
			server.setVpcUuid(server.getVpcUuid());
			server.setSubnetUuid(server.getVSwitchId());

			Image image = imageMap.get(server.getImageUuid());
			if (image != null && !"".equals(image)) {
				server.setOsCategory(image.getOsCategory());
				server.setOsName(image.getOsName());
				server.setOsVersion(image.getOsVersion());
			}
			Flavor flavor = flavorsMap.get(server.getFlavorUuid());
			if (null != flavor) {
				server.setCpu(flavor.getCpu());
				server.setMemory(flavor.getMemory());
			}
			cloudServerRepository.save(server);
			this.updateServerKeyPair(server, keyPairMap);
			// 更新资源表
			updateResource(server, vendor, region.getRegionId(), userId);
			// 更新虚拟机绑定的安全组
			serverSgroupRepository.removeBySid(server.getId());
			if (!ListTool.isEmpty(securityGroups)) {
				updateSgroup(server.getId(), securityGroups, groupMap);
			}
			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);
			// cmdb：删除虚拟机
			serverSgroupRepository.removeBySid(server.getId());
			serverKeyPairRepository.removeBySid(server.getId());
		}
	}

	private void updateServerKeyPair(CloudServer server, Map<String, Long> keyPairMap) throws Exception {
		String keypairName = server.getKeypairName();
		if (null != keypairName && !"".equals(keypairName)) {
			ServerKeypair serverKeypair = new ServerKeypair();
			serverKeypair.setKeypairId(keyPairMap.get(keypairName));
			serverKeypair.setServerId(server.getId());
			serverKeyPairRepository.save(serverKeypair);
		}
	}

	/**
	 * 更新虚拟机安全组
	 *
	 * @param serverId
	 * @param groupMap
	 * @throws Exception
	 */
	private void updateSgroup(Long serverId, List<String> securityGroups, Map<String, Long> groupMap) throws Exception {
		if (!ListTool.isEmpty(securityGroups)) {
			for (String group : securityGroups) {
				ServerSgroup serverSgroup = new ServerSgroup(serverId, groupMap.get(group));
				serverSgroupRepository.save(serverSgroup);
			}
		}
	}

	/**
	 * 更新资源表相关信息
	 *
	 * @param server
	 * @param vendor
	 * @param userId
	 * @throws Exception
	 */
	private void updateResource(CloudServer server, CloudVendor vendor, String region, Long userId) throws Exception {
		// 更新资源表
		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.setMenderId(userId);
			resource.setAccurated(false);
			resource.setAuthed(false);
			resource.setRegionId(region);
			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.setPrivateIps(JSONObject.toJSONString(ips));
			resource.setOwnerId(userId);
			resource.setAccurated(false);
			resource.setRegionId(region);
			resource.setAuthed(false);
			resourceRepository.save(resource);
			server.setResource(resource);
		}
	}

	/**
	 * 同步镜像
	 *
	 * @param models
	 * @param vendor
	 * @param userId
	 * @throws Exception
	 */
	private void syncImage(List<ImageModel> models, Region region, CloudVendor vendor, Long userId) throws Exception {

		if (ListTool.isEmpty(models)) {
			imageRepository.removeByVid(vendor.getId(), region.getRegionId(), userId);
			return;
		}
		List<Image> images = imageRepository.listByVendorId(vendor.getId());
		Map<String, Image> imageMap = Maps.newHashMap();
		for (Image image : images) {
			imageMap.put(image.getImageUuid(), image);
		}
		for (ImageModel model : models) {
			// 去除testg3、hu-2012g3两个系统自带私有镜像
			if ("edf235ca-20d8-4bf6-89d0-fbb4f2f17892".equals(model.getImageUuid())
					|| "8d08657b-3d1b-4bfe-b92d-6e0891126aa7".equals(model.getImageUuid())) {
				continue;
			}
			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 vendor
	 * @param userId
	 * @param serverMap
	 * @throws Exception
	 */
	private void syncVolume(List<VolumeModel> models, CloudVendor vendor, Long userId, Map<String, Long> serverMap,
			Region region) 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.setDevice(model.getDevice());
				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(0L);
			volume.setDevice(model.getDevice());
			volume.setGmtCreate(new Date());
			volume.setVendorId(vendor.getId());
			volume.setRegionId(region.getRegionId());
			volume.setVendorType(vendor.getType());
			volume.setTenantId(0L);
			volume.setProjectId(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);
		}
	}

	public void updateServerDisk(String instanceId, Long vendorId, Integer size) {
		try {
			CloudServer cloudServer = cloudServerRepository.getByInstanceId(instanceId, vendorId);
			if (null != cloudServer) {
				cloudServer.setDisk(size);
				cloudServerRepository.update(cloudServer);
			}
		} catch (Exception e) {
			logger.error("更新虚机系统盘异常： " + e.getMessage());
		}
	}

	/**
	 * 同步安全组
	 *
	 * @param models
	 * @param vendor
	 * @param userId
	 * @throws Exception
	 */
	private void syncSecurityGroup(List<SecurityGroupModel> models, CloudVendor vendor, Long userId, String region,
			Map<String, Vpc> vpcMap) throws Exception {
		// 当安全组为空时,删除数据库残留数据
		if (ListTool.isEmpty(models)) {
			securityGroupRepository.removeByVid(vendor.getId(), region, userId);
			return;
		}
		List<SecurityGroup> groups = securityGroupRepository.listByVendorId(vendor.getId(), region, null);
		Map<String, SecurityGroup> groupMap = Maps.newHashMap();
		for (SecurityGroup group : groups) {
			groupMap.put(group.getGroupUuid(), group);
		}
		for (SecurityGroupModel model : models) {
			SecurityGroup group = new SecurityGroup();
			if (groupMap.containsKey(model.getGroupUuid())) {
				group = groupMap.get(model.getGroupUuid());
				BeanUtils.copyProperties(model, group, "remark");
				group.setMenderId(userId);
				group.setRegionId(region);
				if (vpcMap != null && vpcMap.containsKey(model.getVpcUuid())) {
					group.setVpcId(vpcMap.get(model.getVpcUuid()).getId());
				}
				securityGroupRepository.update(group);
				securityGroupRuleRepository.removeBySgId(group.getId(), userId);
				for (SecurityGroupRuleModel securityGroupRuleModel : model.getModels()) {
					SecurityGroupRule securityGroupRule = new SecurityGroupRule();
					BeanUtils.copyProperties(securityGroupRuleModel, securityGroupRule);
					securityGroupRule.setCreatorId(userId);
					securityGroupRule.setVendorId(vendor.getId());
					securityGroupRule.setGroupId(group.getId());
					securityGroupRule.setGroupUuid(group.getGroupUuid());
					securityGroupRuleRepository.save(securityGroupRule);
				}
				groupMap.remove(model.getGroupUuid());
				continue;
			}
			group = JSONObject.parseObject(JSONObject.toJSONString(model), SecurityGroup.class);
			BeanUtils.copyProperties(model, group, "remark");
			group.preSave(userId, userId, vendor.getId(), 0L, 0L);
			group.setRegionId(region);
			if (vpcMap != null && vpcMap.containsKey(model.getVpcUuid())) {
				group.setVpcId(vpcMap.get(model.getVpcUuid()).getId());
			}
			securityGroupRepository.save(group);
			securityGroupRuleRepository.removeBySgId(group.getId(), userId);
			for (SecurityGroupRuleModel securityGroupRuleModel : model.getModels()) {
				SecurityGroupRule securityGroupRule = new SecurityGroupRule();
				BeanUtils.copyProperties(securityGroupRuleModel, securityGroupRule);
				securityGroupRule.setCreatorId(userId);
				securityGroupRule.setVendorId(vendor.getId());
				securityGroupRule.setGroupId(group.getId());
				securityGroupRule.setGroupUuid(group.getGroupUuid());
				securityGroupRuleRepository.save(securityGroupRule);
			}
		}
		// 删除不存在的安全组
		for (Entry<String, SecurityGroup> entry : groupMap.entrySet()) {
			securityGroupRepository.remove(entry.getValue().getId(), userId);
		}
	}

	/**
	 * 同步虚拟机规格
	 *
	 * @param models
	 * @param vendorId
	 * @throws Exception
	 */
	private void syncInstanceType(List<FlavorModel> models, Long vendorId, 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.getFlavorUuid(), flavor);
		}
		for (FlavorModel model : models) {
			Flavor flavor = new Flavor();
			if (flavorMap.containsKey(model.getFlavorUuid())) {
				flavor = flavorMap.get(model.getFlavorUuid());
				BeanUtils.copyProperties(model, flavor);
				flavor.setRegionId(region.getRegionId());
				flavorRepository.update(flavor);
				flavorMap.remove(model.getFlavorUuid());
				continue;
			}
			BeanUtils.copyProperties(model, flavor);
			flavor.setVendorId(vendorId);
			flavor.setRegionId(region.getRegionId());
			flavorRepository.save(flavor);
			flavorMap.remove(model.getFlavorUuid());
		}
		for (Entry<String, Flavor> entry : flavorMap.entrySet()) {
			flavorRepository.delete(entry.getValue().getId());
		}
	}

	private void syncNetworkCard(Long vendorId, Long userId) throws Exception {

		networkCardRepository.removeByVid(vendorId, userId);

		List<CloudServer> cloudServers = cloudServerRepository.listByVendorId(vendorId);
		for (CloudServer cloudServer : cloudServers) {
			List<String> privateIps = JSONArray.parseArray(cloudServer.getPrivateIps(), String.class);
			for (String privateIp : privateIps) {
				FloatingIp floatingIp = floatingIpRepository.getByFixedIpAddress(privateIp, vendorId);
				NetworkCard networkCard = null;
				if (floatingIp == null) {
					networkCard = new NetworkCard();
					networkCard.setVendorId(vendorId);
					networkCard.setUsed(false);
					networkCard.setIpAddress(privateIp);
					networkCard.setInstanceId(cloudServer.getInstanceId());
					networkCard.setServerName(cloudServer.getName());
					networkCard.setRegionId(cloudServer.getRegionId());
					networkCard.setRegionName(cloudServer.getRegionName());
				}
				networkCardRepository.save(networkCard);
			}
		}
	}

	/**
	 * @author Hu Wentao
	 * @date 2020/10/30 13:14
	 * @Description: 同步网卡
	 */
	private void syncNetworkCard(List<NetworkCardModel> models, Map<String, String> networkCardMap, Long vendorId,
			Long userId, Region region) throws Exception {
		if (models.isEmpty()) {
			networkCardRepository.removeByVid(vendorId, userId);
			return;
		}
		List<NetworkCard> listByVendor = networkCardRepository.listByVendor(vendorId, region.getRegionId());
		Map<String, NetworkCard> networkCardHashMap = Maps.newHashMap();
		for (NetworkCard networkCard : listByVendor) {
			networkCardHashMap.put(networkCard.getNetworkcardUuid(), networkCard);
		}

		NetworkCard networkCard = null;
		for (NetworkCardModel networkCardModel : models) {
			if (networkCardHashMap.containsKey(networkCardModel.getNetworkcardUuid())) {
				networkCard = networkCardHashMap.get(networkCardModel.getNetworkcardUuid());
				BeanUtils.copyProperties(networkCardModel, networkCard);
				networkCard.setRegionId(region.getRegionId());
				networkCard.setVendorId(vendorId);
				networkCard.setMenderId(userId);
				if (networkCardMap.containsKey(networkCardModel.getNetworkcardUuid())) {
					networkCard.setUsed(true);
					networkCard.setFloatingIpUuid(networkCardMap.get(networkCardModel.getNetworkcardUuid()));
				} else {
					networkCard.setUsed(false);
				}
				networkCardRepository.update(networkCard);
				networkCardHashMap.remove(networkCardModel.getNetworkcardUuid());
				continue;
			}
			networkCard = new NetworkCard();
			BeanUtils.copyProperties(networkCardModel, networkCard);
			networkCard.setRegionId(region.getRegionId());
			networkCard.setVendorId(vendorId);
			networkCard.setMenderId(userId);
			if (networkCardMap.containsKey(networkCardModel.getNetworkcardUuid())) {
				networkCard.setUsed(true);
				networkCard.setFloatingIpUuid(networkCardMap.get(networkCardModel.getNetworkcardUuid()));
			} else {
				networkCard.setUsed(false);
			}
			networkCardRepository.save(networkCard);
		}

		for (Entry<String, NetworkCard> entry : networkCardHashMap.entrySet()) {
			networkCardRepository.remove(entry.getValue().getId(), userId);
		}

	}

	/**
	 * 同步域
	 *
	 * @param regionModels
	 * @param
	 * @param
	 * @throws Exception
	 */
	private void syncRegion(List<RegionModel> regionModels, Region region, CloudVendor vendor, Long userId)
			throws Exception {
		if (ListTool.isEmpty(regionModels)) {
			regionRepository.deleteByVid(vendor.getId(), region.getRegionId());
			zoneRepository.deleteByRegionId(region.getRegionId(), vendor.getId());
			return;
		}
		for (RegionModel model : regionModels) {
			syncZone(model.getZones(), model.getCode(), vendor, userId);
		}
	}

	/**
	 * 同步域下面的区
	 */
	private void syncZone(List<ZoneModel> models, String regionId, CloudVendor vendor, Long userId) throws Exception {
		zoneRepository.deleteByRegionId(regionId, 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);
			}
		}
	}

	private void syncCluster(List<ClusterModel> models, CloudVendor vendor, Long userId, Region region)
			throws Exception {

		clusterRepository.deleteByVendor(vendor.getId());

		List<Cluster> clusters = models.stream().map(model -> {
			Cluster cluster = new Cluster();

			BeanUtils.copyProperties(model, cluster);
			cluster.setCreatorId(userId);
			cluster.setVendorId(vendor.getId());
			cluster.setType(vendor.getType());
			cluster.setCpuExcessRatio(10L);
			cluster.setGuid(IDFactory.instance().uuid());
			return cluster;
		}).collect(Collectors.toList());

		clusterRepository.batchSave(clusters, clusters.size());
	}

	/**
	 * 同步vpc专用网络
	 *
	 * @param models
	 * @param vendorId
	 * @param userId
	 * @throws Exception
	 */
	private void syncVpc(List<VpcModel> models, Long vendorId, Long userId, Region region) throws Exception {
		if (ListTool.isEmpty(models)) {
			vpcRepository.deleteByVid(vendorId, region.getRegionId(), userId);
			return;
		}
		List<Vpc> vpcs = vpcRepository.list(vendorId, region.getRegionId());
		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.getRegionId());
				vpcRepository.update(vpc);
				vpcMap.remove(model.getVpcId());
				continue;
			}
			BeanUtils.copyProperties(model, vpc);
			vpc.setCreatorId(userId);
			vpc.setVendorId(vendorId);
			vpc.setRegionId(region.getRegionId());
			vpc.setTenantId(0L);
			vpc.setProjectId(0L);
			vpcRepository.save(vpc);
			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 syncKeypair(List<KeypairModel> models, String regionId, Long vendorId, Long userId) throws Exception {
		if (ListTool.isEmpty(models)) {
			keypairRepository.removeByVid(vendorId, regionId, userId);
			return;
		}
		List<Keypair> keypairs = keypairRepository.listByVid(vendorId, regionId);
		Map<String, Keypair> keypairMap = Maps.newHashMap();
		for (Keypair keypair : keypairs) {
			if (keypairMap.containsKey(keypair.getName())) {
				keypairRepository.remove(keypair.getId(), userId);
			} else {
				keypairMap.put(keypair.getName(), keypair);
			}
		}
		for (KeypairModel model : models) {
			Keypair keypair = new Keypair();
			if (keypairMap.containsKey(model.getName())) {
				keypair = keypairMap.get(model.getName());
				model.setGmtCreate(keypair.getGmtCreate());
				model.setUserUuid(keypair.getUserUuid());
				BeanUtils.copyProperties(model, keypair);
				keypair.setMenderId(userId);
				keypair.setVendorId(vendorId);
				keypair.setRegionId(regionId);
				keypair.setGmtModify(new Date());
				keypairRepository.update(keypair);
				keypairMap.remove(model.getName());
				continue;
			}
			BeanUtils.copyProperties(model, keypair);
			keypair.setCreatorId(userId);
			keypair.setGmtCreate(new Date());
			keypair.setVendorId(vendorId);
			keypair.setRegionId(regionId);
			keypair.setVendorId(vendorId);
			keypair.setTenantId(0L);
			keypair.setProjectId(0L);
			keypairRepository.save(keypair);
			keypairMap.remove(model.getName());
		}
		for (Entry<String, Keypair> entry : keypairMap.entrySet()) {
			keypairRepository.remove(entry.getValue().getId(), userId);
		}
	}
}
