package com.bocloud.ims.service.builder;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

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.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.Resource;
import com.bocloud.ims.entity.resource.ResourceEvent;
import com.bocloud.ims.entity.resource.ResourceGroup;
import com.bocloud.ims.entity.resource.SecurityGroup;
import com.bocloud.ims.entity.resource.ServerKeypair;
import com.bocloud.ims.entity.resource.ServerLabel;
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.repository.resource.CloudServerRepository;
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.ResourceEventRepository;
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.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.service.utils.PwdRandom;
import com.google.common.collect.Lists;

public class TianyiServerBuilder 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 KeypairRepository keypairRepository;
	private SecurityGroupRepository securityGroupRepository;
	private ServerSgroupRepository serverSgroupRepository;
	private ServerKeypairRepository serverKeypairRepository;
	private FlavorRepository flavorRepository;
	private SubnetRepository subnetRepository;
	private FloatingIpRepository floatingIpRepository;
	private ResourceGroupRepository resourceGroupRepository;
	private NetworkCardRepository networkCardRepository;
	private ServerLabelRepository serverLabelRepository;

	public TianyiServerBuilder(CloudServerRepository cloudServerRepository, ResourceRepository resourceRepository,
			ResourceEventRepository resourceEventRepository, ImageRepository imageRepository,
			VolumeRepository volumeRepository, ServerDriver serverDriver, RequestContext context, CloudVendor vendor,
			KeypairRepository keypairRepository, SecurityGroupRepository securityGroupRepository,
			ServerSgroupRepository serverSgroupRepository, ServerKeypairRepository serverKeypairRepository,
			FlavorRepository flavorRepository, SubnetRepository subnetRepository,
			FloatingIpRepository floatingIpRepository, ResourceGroupRepository resourceGroupRepository,
			NetworkCardRepository networkCardRepository, ServerLabelRepository serverLabelRepository) {
		super();
		this.keypairRepository = keypairRepository;
		this.securityGroupRepository = securityGroupRepository;
		this.serverSgroupRepository = serverSgroupRepository;
		this.serverKeypairRepository = serverKeypairRepository;
		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.flavorRepository = flavorRepository;
		this.subnetRepository = subnetRepository;
		this.floatingIpRepository = floatingIpRepository;
		this.resourceGroupRepository = resourceGroupRepository;
		this.networkCardRepository = networkCardRepository;
		this.serverLabelRepository = serverLabelRepository;
	}

	@Override
	public BocloudResult<ServerModel> prepare(JSONObject object) throws Exception {
		// 虚拟机名
		String name = object.getString(Common.NAME);
		// 描述
		String remark = object.getString("remark");
		model = new ServerModel(name, remark);
		Integer internetMaxBandwidthIn = object.getInteger("internetMaxBandwidthIn");
		Integer internetMaxBandwidthOut = object.getInteger("internetMaxBandwidthOut");
		if (null == internetMaxBandwidthIn || 0 == internetMaxBandwidthIn) {
			internetMaxBandwidthIn = 10;
		}
		if (null == internetMaxBandwidthOut || 0 == internetMaxBandwidthOut) {
			internetMaxBandwidthOut = 10;
		}
		model.setHostName("root");
		String resourceGroupUuid = object.getString("resourceGroupUuid");
		if (!StringUtils.isEmpty(resourceGroupUuid)) {
			ResourceGroup resourceGroup = resourceGroupRepository.getByGroupUuid(object.getLong("vendorId"),
					resourceGroupUuid);
			if (null == resourceGroup) {
				return new BocloudResult<>(false, "资源组不存在");
			}
			model.setResourceGroupUuid(resourceGroupUuid);
		}

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

		Integer systemDiskSize = object.getInteger("systemDiskSize");
		if (null == systemDiskSize) {
			systemDiskSize = object.getInteger("rootSize");
		}
		if (null == systemDiskSize || systemDiskSize < imageMinDisk) {
			return new BocloudResult<>(false, "系统盘大小不允许小于镜像盘允许的最小值");
		}
		model.setImageType(image.getOsCategory());
		model.setDisk(systemDiskSize);
		model.setSystemDiskSize(systemDiskSize);

		// 虚拟机标签
		if (!StringUtils.isEmpty(object.getString("labelIds"))) {
			List<Long> labelIds = JSONArray.parseArray(object.getString("labelIds"), Long.class);
			model.setLabelIds(labelIds);
		}

		// 目前只有"SAS"、"SSD"
		model.setDiskType(object.getString("diskType"));

		String systemDiskCategory = object.getString("systemDiskCategory");

		String dataDisk = object.getString("diskDevices");
		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 != null && !"".equals(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 instanceChargeType = object.getString("instanceChargeType");
		if (null == instanceChargeType || "".equals(instanceChargeType)) {
			instanceChargeType = "PostPaid";
		}
		String instanceType = object.getString("instanceType");
		if (StringUtils.isEmpty(instanceType)) {
			Flavor flavor = flavorRepository.query(object.getLong("flavorId"));
			if (null == flavor) {
				return new BocloudResult<>(false, "无效的规格参数！");
			}
			instanceType = flavor.getFlavorUuid();
		}
		model.setName(object.getString("name"));
		model.setInstanceChargeType(instanceChargeType);
		model.setVpcUuid(object.getString("vpcUuid"));
		String subnetUuid = object.getString("subnetId");
		if (!StringUtils.isEmpty(subnetUuid)) {
			Subnet subnet = subnetRepository.query(object.getLong("subnetId"));
			if (null == subnet) {
				return new BocloudResult<>(false, "无效的子网参数！");
			}
			subnetUuid = subnet.getSubnetUuid();
		}
		// 批量创建：外层有循环，这里直接写死给1
		model.setCount(1);
		model.setSubnetUuid(subnetUuid);

		String password = object.getString("password");
		String keypairName = object.getString("keypairName");

		// 如果未设置密码则随机生成并保存
		if (StringUtils.isEmpty(keypairName) && StringUtils.isEmpty(password)) {
			password = randomStr(12);
		}

		model.setKeypairName(keypairName);

		List<String> groups = JSONArray.parseArray(object.getString("groups"), String.class);
		model.setSecurityGroups(groups);

		model.prepareData("root", password, object.getString(Common.REGIONID), object.getString("zoneId"),
				image.getImageUuid(), instanceType, object.getString("groups"), object.getString("internetChargeType"),
				internetMaxBandwidthIn, internetMaxBandwidthOut, systemDiskSize, systemDiskCategory, dataDisk);
		return new BocloudResult<ServerModel>(true, model, "success");
	}

	@Override
	public BocloudResult<CloudServer> builder(CloudServer cloudServer) throws Exception {
		// 创建虚拟机
		BocloudResult result = serverDriver.create(vendor.getUuid(), model.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.setRegionId(server.getRegionId());
			cloudServer.setInstanceId(server.getInstanceId());
			cloudServer.setUuid(server.getUuid());
			cloudServer.setDisk(model.getDisk());
			cloudServer.setMemory(server.getMemory());
			cloudServer.setCpu(server.getCpu());
			cloudServer.setGmtVmCreate(server.getGmtVmCreate());
			cloudServer.setPrivateIps(server.getPrivateIps());
			cloudServer.setManagerIp(server.getPrivateIps());
			cloudServer.setFlavorUuid(server.getFlavorUuid());
			cloudServer.setOsName(server.getOsName());
			cloudServer.setRegionId(server.getRegionId());
			cloudServer.setNetcards(server.getNetcards());
			cloudServer.setVpcUuid(server.getVpcUuid());
			cloudServer.setSubnetUuid(server.getVSwitchId());

			cloudServer.setZone(model.getZone());
			cloudServer.setPswd(model.getPassword());
			String imageUuid = cloudServer.getImageUuid();
			Image image = imageRepository.queryByImageUuid(imageUuid);
			cloudServer.setImageUuid(imageUuid);
			cloudServer.setOsCategory(image.getOsCategory());
			cloudServer.setOsName(image.getOsName());
			cloudServer.setOsVersion(image.getOsVersion());
			String state = server.getStatus();
			if ("Running".equalsIgnoreCase(state)) {
				cloudServer.setStatus(BocloudStatus.Server.RUNNING.name());
			} else if ("Stopped".equalsIgnoreCase(state)) {
				cloudServer.setStatus(BocloudStatus.Server.STOPPED.name());
			}
			cloudServer.setRecycle(false);
			cloudServer.setPublicIps(server.getPublicIps());

			cloudServer.setLabelIds(server.getLabelIds());
			// 保存标签信息
			List<Long> labelIds = model.getLabelIds();
			if (!ListTool.isEmpty(labelIds)) {
				List<ServerLabel> serverLabels = Lists.newArrayList();
				for (Long labelId : labelIds) {
					serverLabels.add(new ServerLabel(cloudServer.getId(), labelId, "VM", vendor.getId()));
				}
				if (!ListTool.isEmpty(serverLabels)) {
					serverLabelRepository.batchSave(serverLabels);
				}
			}

			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);
					}
					if (volume.getBootVolume()) {
						volume.setBootVolume(true);
						volume.setDeleteWithInstance(true);
					} else {
						volume.setBootVolume(false);
						volume.setDeleteWithInstance(false);
					}
					volume.setServerId(cloudServer.getId());
					volume.setRegionId(server.getRegionId());
					volumeRepository.save(volume);
				}
			}
			List<Volume> listByServerId = volumeRepository.listByServerId(cloudServer.getId());
			cloudServer.setDiskDevices(listByServerId);
			// 保存资源T
			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);
				}
			}
			List<String> securityGroups = cloudServer.getSecurityGroups() == null ? new ArrayList<String>()
					: cloudServer.getSecurityGroups();
			for (String securityGroup : securityGroups) {
				SecurityGroup group = securityGroupRepository.getByGroupId(securityGroup, vendor.getId());
				if (null != group) {
					ServerSgroup serverSgroup = new ServerSgroup(cloudServer.getId(), group.getId());
					serverSgroupRepository.save(serverSgroup);
				}
			}
			// 保存 秘钥
			if (!StringUtils.isEmpty(model.getKeypairName())) {
				updateServerKeyPair(cloudServer, vendor.getId(), model.getKeypairName());
			}
			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.preSave(cloudServer.getName(), cloudServer.getStatus(), userId, context.getTenant(),
						context.getProject());
				resource.setInventory(JSONObject.toJSONString(cloudServer));
				resource.setRegionId(cloudServer.getRegionId());
				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.setRegionId(cloudServer.getRegionId());
				resource.setPrivateIps(JSONObject.toJSONString(ips));
				resourceRepository.update(resource);
			}
		} else {
			event = new ResourceEvent(cloudServer.getId(), handler, "创建失败：" + result.getMessage(), 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, String keyPairName) throws Exception {
		String keypairName = server.getKeypairName();
		if (null != keypairName && !"".equals(keypairName) && !"null".equalsIgnoreCase(keypairName)) {
			ServerKeypair serverKeypair = new ServerKeypair();
			Keypair keypair = keypairRepository.getByName(keyPairName, vendorId, server.getRegionId());
			if (null != keypair) {
				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);
	}

}
