package com.bocloud.ims.service.builder;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.compute.ServerDriver;
import com.bocloud.cmp.entity.enums.BocloudStatus;
import com.bocloud.cmp.entity.enums.ResourceCategory;
import com.bocloud.cmp.entity.enums.VolumeCategory;
import com.bocloud.cmp.model.NetworkCardModel;
import com.bocloud.cmp.model.ServerModel;
import com.bocloud.common.enums.ResourceCatalog;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.utils.Common;
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.Flavor;
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.Resource;
import com.bocloud.ims.entity.resource.ResourceEvent;
import com.bocloud.ims.entity.resource.SecurityGroup;
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.repository.resource.CloudServerRepository;
import com.bocloud.ims.repository.resource.FlavorRepository;
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.ResourceEventRepository;
import com.bocloud.ims.repository.resource.ResourceRepository;
import com.bocloud.ims.repository.resource.SecurityGroupRepository;
import com.bocloud.ims.repository.resource.ServerKeypairRepository;
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.service.utils.PwdRandom;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class TencentServerBuilder implements ServerBuilder {

	private CloudServerRepository cloudServerRepository;
	private ResourceRepository resourceRepository;
	private ResourceEventRepository resourceEventRepository;
	private ImageRepository imageRepository;
	private VolumeRepository volumeRepository;
	private ServerDriver serverDriver;
	private RequestContext context;
	private CloudVendor vendor;
	private ServerModel model;
	private VpcRepository vpcRepository;
	private FlavorRepository flavorRepository;
	private SubnetRepository subnetRepository;
	private KeypairRepository keypairRepository;
	private SecurityGroupRepository securityGroupRepository;
	private ServerSgroupRepository serverSgroupRepository;
	private ServerKeypairRepository serverKeypairRepository;
	private NetworkCardRepository networkCardRepository;

	public TencentServerBuilder(CloudServerRepository cloudServerRepository, ResourceRepository resourceRepository,
			ResourceEventRepository resourceEventRepository, ImageRepository imageRepository,
			VolumeRepository volumeRepository, ServerDriver serverDriver, RequestContext context, CloudVendor vendor,
			VpcRepository vpcRepository, FlavorRepository flavorRepository, SubnetRepository subnetRepository,
			KeypairRepository keypairRepository, SecurityGroupRepository securityGroupRepository,
			ServerSgroupRepository serverSgroupRepository, ServerKeypairRepository serverKeypairRepository,
			NetworkCardRepository networkCardRepository) {
		super();
		this.cloudServerRepository = cloudServerRepository;
		this.resourceRepository = resourceRepository;
		this.resourceEventRepository = resourceEventRepository;
		this.imageRepository = imageRepository;
		this.volumeRepository = volumeRepository;
		this.serverDriver = serverDriver;
		this.context = context;
		this.vendor = vendor;
		this.vpcRepository = vpcRepository;
		this.flavorRepository = flavorRepository;
		this.subnetRepository = subnetRepository;
		this.keypairRepository = keypairRepository;
		this.securityGroupRepository = securityGroupRepository;
		this.serverSgroupRepository = serverSgroupRepository;
		this.serverKeypairRepository = serverKeypairRepository;
		this.networkCardRepository = networkCardRepository;
	}

	@Override
	public BocloudResult<ServerModel> prepare(JSONObject object) throws Exception {
		String name = object.getString(Common.NAME);// 虚拟机名
		String remark = object.getString("remark");// 描述
		String instanceChargeType = object.getString("instanceChargeType");
		if (null != instanceChargeType && "PREPAID".equalsIgnoreCase(instanceChargeType)) {
			return new BocloudResult<>(false, "包年包月业务暂未开放");
		}
		model = new ServerModel(name, remark);
		String regionId = object.getString("regionId");
		if (null != regionId && !"".equals(regionId)) {
			model.setRegionId(regionId);
		}
		String groups = object.getString("groups");
		if (null != groups && !"".equals(groups)) {
			List<String> securityGroups = JSON.parseArray(groups, String.class);
			model.setSecurityGroups(securityGroups);
		}
		model.setInstanceChargeType(instanceChargeType);

		Image image = imageRepository.query(object.getLong("imageId"));
		if (null == image) {
			return new BocloudResult<>(false, "镜像不存在");
		}

		String account = "root";
		if ("Windows".equalsIgnoreCase(image.getOsType())) {
			account = "Administrator";
		}

		Integer systemDiskSize = 0;
		if (object.containsKey("rootSize")) {
			systemDiskSize = object.getInteger("rootSize"); // 管理端可以指定系统盘大小
		} else if (object.containsKey("disk")) {
			Integer disk = object.getInteger("disk"); // 自服务端根据规格取系统盘大小
			int imageMinDisk = image.getMinDisk().intValue();
			if (disk < imageMinDisk) {
				return new BocloudResult<>(false, "系统盘大小能小于镜像盘大小");
			}
			systemDiskSize = disk;
		} else {
			systemDiskSize = image.getMinDisk().intValue(); // 容错
		}
		model.setDisk(systemDiskSize);
		String systemDiskCategory = object.getString("systemDiskCategory");
		if (StringUtils.isEmpty(systemDiskCategory)) {
			systemDiskCategory = "cloud";
		} else {
			if (VolumeCategory.CLOUD.name().equals(systemDiskCategory)) {
				systemDiskCategory = "cloud";
			} else if (VolumeCategory.EFFICIENCY.name().equals(systemDiskCategory)) {
				systemDiskCategory = "cloud_efficiency";
			} else if (VolumeCategory.SSD.name().equals(systemDiskCategory)) {
				systemDiskCategory = "cloud_ssd";
			}
		}
		String dataDisk = object.getString("dataDisk");
		if (!StringUtils.isEmpty(dataDisk)) {
			JSONArray jsonArray = new JSONArray();
			List<Object> list = JSONArray.parseArray(dataDisk);
			for (Object obj : list) {
				JSONObject jsonObject = JSONObject.parseObject(obj.toString());
				String dataDiskCategory = jsonObject.getString("dataDiskCategory");
				if (dataDiskCategory.equals(VolumeCategory.CLOUD.name())) {
					jsonObject.put("dataDiskCategory", "cloud");
				} else if (dataDiskCategory.equals(VolumeCategory.EFFICIENCY.name())) {
					jsonObject.put("dataDiskCategory", "cloud_efficiency");
				} else if (dataDiskCategory.equals(VolumeCategory.SSD.name())) {
					jsonObject.put("dataDiskCategory", "cloud_ssd");
				} else {
					jsonObject.put("dataDiskCategory", "cloud");
				}
				jsonArray.add(jsonObject);
			}
			dataDisk = jsonArray.toJSONString();
		}
		String networkId = null;
		String subnetUuid = null;
		Long vendorId = object.getLong(Common.VENDORID);
		Long subnetId = object.getLong("subnetId");
		Long vpcId = object.getLong("networkId");
		if (null != vpcId && vpcId > 0) {
			Vpc vpc = vpcRepository.query(vpcId);
			if (null != vpc) {
				networkId = vpc.getVpcId();
				Subnet subnet = subnetRepository.query(subnetId);
				subnetUuid = subnet.getSubnetUuid();
			}
		} else {
			String vpcUuid = object.getString("vpcUuid");
			Vpc vpc = vpcRepository.getByUuid(vpcUuid, vendorId);
			if (null != vpc) {
				networkId = vpc.getVpcId();
				subnetUuid = object.getString("subnetUuid");
				Subnet subnet = subnetRepository.getBySubId(subnetUuid, vendorId);
				if (null == subnet) {
					return new BocloudResult<>(false, "网络不存在");
				}
			}
		}
		Long flavorId = object.getLong("flavorId");
		Flavor flavor = flavorRepository.query(flavorId);
		if (null == flavor) {
			return new BocloudResult<>(false, "规格不存在");
		}
		String keypairName = null;
		String keyName = object.getString("keypairName");
		if (null != keyName && !"".equals(keyName)) {
			Keypair keypair = keypairRepository.getByName(keyName, vendorId);
			if (null != keypair) {
				keypairName = keypair.getFingerprint();
			}
		}
		String password = object.getString("password");
		if (StringUtils.isEmpty(keypairName) && StringUtils.isEmpty(password)) {
			password = randomStr(12);
		}
		// 虚拟机标签
		if (!StringUtils.isEmpty(object.getString("labelIds"))) {
			List<Long> labelIds = JSONArray.parseArray(object.getString("labelIds"), Long.class);
			model.setLabelIds(labelIds);
		}
		model.prepareData(account, password, object.getString("zoneId"), image.getImageUuid(),
				object.getString("period"), object.getString("groups"), systemDiskSize, null, flavor.getFlavorUuid(),
				networkId, subnetUuid, keypairName);
		return new BocloudResult<ServerModel>(true, model, "success");
	}

	@Override
	public BocloudResult<CloudServer> builder(CloudServer cloudServer) throws Exception {
		// 创建虚拟机
		BocloudResult result = serverDriver.create(vendor.getUuid(), cloudServer.getRegionId(), model);
		// 操作记录
		Long userId = context.getTarget();
		String handler = "虚拟机创建";
		ResourceEvent event = null;
		if (result.isSuccess()) {
			event = new ResourceEvent(cloudServer.getId(), handler, "成功", userId, new Date(), "VM", vendor.getId(),
					context.getCatalog());
			String content = JSONObject.toJSONString(result.getData());
			CloudServer server = JSONObject.parseObject(content, CloudServer.class);
			cloudServer.setInstanceId(server.getInstanceId());
			cloudServer.setUuid(server.getUuid());
			cloudServer.setDisk(server.getSystemDiskSize());
			cloudServer.setMemory(server.getMemory());
			cloudServer.setCpu(server.getCpu());
			cloudServer.setGmtVmCreate(server.getGmtVmCreate());
			cloudServer.setManagerIp(server.getManagerIp());
			cloudServer.setPrivateIps(server.getPrivateIps());
			cloudServer.setPublicIps(server.getPublicIps());
			cloudServer.setZone(server.getZone());
			cloudServer.setInstanceChargeType(server.getInstanceChargeType());
			cloudServer.setInternetChargeType(server.getInternetChargeType());
			cloudServer.setRegionId(server.getRegionId());
			cloudServer.setInternetMaxBandwidthOut(server.getInternetMaxBandwidthOut());
			cloudServer.setOsName(server.getOsName());
			cloudServer.setOsVersion(server.getOsVersion());
			cloudServer.setSubnetUuid(server.getSubnetUuid());
			cloudServer.setSystemDiskCategory(server.getSystemDiskCategory());
			cloudServer.setSystemDiskSize(server.getSystemDiskSize());
			cloudServer.setNetworkUuid(server.getNetworkUuid());
			cloudServer.setFlavorUuid(server.getFlavorUuid());
			cloudServer.setImageUuid(server.getImageUuid());
			cloudServer.setPswd(model.getPassword());
			cloudServer.setDisk(server.getSystemDiskSize());
			cloudServer.setVendorType(vendor.getType());
			// 新创建的虚拟机 秘钥 同步不回来 所以直接采用model中的秘钥数据
			String keypairName = model.getKeypairName();
			if (null != keypairName && !"".equals(keypairName)) {
				List<String> keyPairList = new ArrayList<>();
				keyPairList.add(keypairName);
				cloudServer.setKeypairName(JSON.toJSONString(keyPairList));
			}
			// 系统类型、
			Image image = imageRepository.getByImageUuid(server.getImageUuid());
			if (null != image) {
				cloudServer.setOsCategory(image.getOsCategory());
			}
			String state = server.getStatus();
			if (state.equalsIgnoreCase(BocloudStatus.Server.RUNNING.name())) {
				cloudServer.setStatus(BocloudStatus.Server.RUNNING.name());
			} else if (state.equalsIgnoreCase(BocloudStatus.Server.STOPPED.name())) {
				cloudServer.setStatus(BocloudStatus.Server.STOPPED.name());
			}
			cloudServer.setRecycle(false);
			cloudServerRepository.update(cloudServer);
			List<Volume> volumeModels = server.getDiskDevices();
			if (!ListTool.isEmpty(volumeModels)) {
				for (Volume volume : volumeModels) {
					volume.setCreatorId(userId);
					volume.setGmtCreate(new Date());
					volume.setVendorId(vendor.getId());
					volume.setVendorType(vendor.getType());
					volume.setTenantId(cloudServer.getTenantId() == null ? 0L : cloudServer.getTenantId());
					Long projectId = cloudServer.getProjectId();
					if (null != projectId && projectId > 0) {
						volume.setProjectId(projectId);
					}
					volume.setRegionId(server.getRegionId());
					volume.setServerId(cloudServer.getId());
					volume.setName(volume.getVolumeUuid());
					volume.setServerId(cloudServer.getId());
					volumeRepository.save(volume);
				}
			}
			List<Volume> listByServerId = volumeRepository.listByServerId(cloudServer.getId());
			if (null != listByServerId && listByServerId.size() > 0) {
				cloudServer.setDiskDevices(listByServerId);
			}

			List<String> secuList = JSONObject.parseArray(JSON.toJSONString(model.getSecurityGroups()), String.class);
			for (String securityGroup : secuList) {
				SecurityGroup group = securityGroupRepository.getByGroupId(securityGroup);
				ServerSgroup serverSgroup = new ServerSgroup(cloudServer.getId(), group.getId());
				serverSgroupRepository.save(serverSgroup);
			}
			List<NetworkCardModel> networkCards = server.getNetworkCards();
			if (!ListTool.isEmpty(networkCards)) {
				for (NetworkCardModel networkCardModel : networkCards) {
					NetworkCard networkCard = new NetworkCard();
					BeanUtils.copyProperties(networkCardModel, networkCard);
					networkCard.setMenderId(userId);
					networkCard.setRegionId(cloudServer.getRegionId());
					networkCard.setCategory("VM");
					networkCard.setGmtModify(new Date());
					networkCard.setVendorId(cloudServer.getVendorId());
					networkCardRepository.save(networkCard);
				}
			}
			// 保存 秘钥
			updateServerKeyPair(cloudServer, vendor.getId());
			// 保存资源
			List<String> ips = Lists.newArrayList();
			if (!StringUtils.isEmpty(server.getPrivateIps())) {
				List<String> objects = JSONObject.parseArray(server.getPrivateIps(), String.class);
				for (String ip : objects) {
					ips.add(ip);
				}
			}
			Resource resource = resourceRepository.query(ResourceCategory.Computer.name(),
					ResourceCatalog.LOGICAL.name(), cloudServer.getId());
			if (null == resource) {
				resource = new Resource(ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(),
						cloudServer.getId(), JSONObject.toJSONString(ips), cloudServer.getOsCategory(), vendor.getId());
				resource.setRegionId(cloudServer.getRegionId());
				resource.preSave(cloudServer.getName(), cloudServer.getStatus(), userId, context.getTenant(),
						context.getProject());
				resource.setInventory(JSONObject.toJSONString(cloudServer));
				resourceRepository.save(resource);
			} else {
				resource.setInventory(JSONObject.toJSONString(cloudServer));
				resource.setStatus(cloudServer.getStatus());
				resource.setMenderId(userId);
				resource.setCreatorId(userId);
				resource.setGmtModify(new Date());
				resource.setGmtCreate(new Date());
				resource.setPrivateIps(JSONObject.toJSONString(ips));
				resource.setRegionId(cloudServer.getRegionId());
				resourceRepository.update(resource);
			}
		} else {
			event = new ResourceEvent(cloudServer.getId(), handler, "失败", userId, new Date(), "VM", vendor.getId(),
					context.getCatalog());
			cloudServerRepository.remove(cloudServer.getId(), context.getTarget());
		}
		resourceEventRepository.save(event);
		return result.isSuccess() ? new BocloudResult<>(true, cloudServer, "success")
				: new BocloudResult<>(false, cloudServer, result.getMessage());
	}

	private void updateServerKeyPair(CloudServer server, Long vendorId) throws Exception {
		String keypairName = server.getKeypairName();
		if (null != keypairName && !"".equals(keypairName) && !"null".equalsIgnoreCase(keypairName)) {
			List<String> keyPairList = JSON.parseArray(keypairName, String.class);
			ServerKeypair serverKeypair = null;
			for (String keyName : keyPairList) {
				if (null != keyName && !"".equals(keyName) && !"null".equalsIgnoreCase(keyName)) {
					serverKeypair = new ServerKeypair();
					Keypair keypair = keypairRepository.getByFingerprint(keyName, vendorId);
					serverKeypair.setKeypairId(keypair.getId());
					serverKeypair.setServerId(server.getId());
					serverKeypairRepository.save(serverKeypair);
				}
			}
		}
	}

	/**
	 * 返回随机字符串，同时包含数字、大小写字母
	 *
	 * @param len 字符串长度，不能小于3
	 * @return String 随机字符串
	 */
	public static String randomStr(int len) {
		if (len < 3) {
			throw new IllegalArgumentException("字符串长度不能小于3");
		}
		// 数组，用于存放随机字符
		char[] chArr = new char[len];
		// 为了保证必须包含数字、大小写字母
		chArr[0] = (char) ('0' + PwdRandom.uniform(0, 10));
		chArr[1] = (char) ('A' + PwdRandom.uniform(0, 26));
		chArr[2] = (char) ('a' + PwdRandom.uniform(0, 26));

		char[] codes = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
				'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
				'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
				'z' };
		// charArr[3..len-1]随机生成codes中的字符
		for (int i = 3; i < len; i++) {
			chArr[i] = codes[PwdRandom.uniform(0, codes.length)];
		}

		// 将数组chArr随机排序
		for (int i = 0; i < len; i++) {
			int r = i + PwdRandom.uniform(len - i);
			char temp = chArr[i];
			chArr[i] = chArr[r];
			chArr[r] = temp;
		}

		return new String(chArr);
	}

}
