package com.bocloud.ims.service.builder;

import com.alibaba.fastjson.JSON;
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.model.ServerModel;
import com.bocloud.common.enums.ResourceCatalog;
import com.bocloud.common.model.BocloudResult;
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.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.SecurityGroup;
import com.bocloud.ims.entity.resource.ServerKeypair;
import com.bocloud.ims.entity.resource.ServerSgroup;
import com.bocloud.ims.entity.resource.Volume;
import com.bocloud.ims.repository.resource.CloudServerRepository;
import com.bocloud.ims.repository.resource.ImageRepository;
import com.bocloud.ims.repository.resource.KeypairRepository;
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.VolumeRepository;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;

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

public class KingCloudServerBuilder 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;

	public KingCloudServerBuilder(CloudServerRepository cloudServerRepository, ResourceRepository resourceRepository,
			ResourceEventRepository resourceEventRepository, ImageRepository imageRepository,
			VolumeRepository volumeRepository, ServerDriver serverDriver, RequestContext context, CloudVendor vendor,
			KeypairRepository keypairRepository, SecurityGroupRepository securityGroupRepository,
			ServerSgroupRepository serverSgroupRepository, ServerKeypairRepository serverKeypairRepository) {
		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;
	}

	@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);

		model.setSubnetUuid(object.getString("subnetUuid"));
		model.setRegionId(object.getString("regionId"));
		model.setZone(object.getString("zone"));
		model.setFlavorUuid(object.getString("flavorUuid"));

		Image image = imageRepository.query(object.getLong("imageId"));
		if (null == image) {
			return new BocloudResult<>(false, "镜像不存在");
		}
		model.setImageUuid(image.getImageUuid());
		// 计费方式
		String instanceChargeType = object.getString("instanceChargeType");
		if (null == instanceChargeType || "".equals(instanceChargeType)) {
			// 有效值：Monthly(包年包月）、Daily（按日月结)、 HourlyInstantSettlement（按小时实时结算）
			instanceChargeType = "HourlyInstantSettlement";
		}
		model.setInstanceChargeType(instanceChargeType);
		// 秘钥/密码
		String password = object.getString("password");
		if (null != password) {
			model.setPassword(password);
		} else {
			String keypairs = object.getString("keypairs");
			String[] keypairsArray = JSON.parseObject(keypairs, String[].class);
			if (null != keypairsArray && keypairsArray.length > 0) {
				model.setKeypairIds(keypairsArray);
			}
		}
		// 安全组
		String groups = object.getString("groups");
		List<String> securityGroups = new ArrayList<>();
		securityGroups.add(groups);
		model.setSecurityGroups(securityGroups);
		// 数据盘
		JSONObject dataDisks = new JSONObject();
		String dataDiskParam = object.getString("dataDisks");
		List<JSONObject> dataDiskArray = JSONObject.parseArray(dataDiskParam, JSONObject.class);
		if (null != dataDiskArray && dataDiskArray.size() > 0) {
			for (int i = 0; i < dataDiskArray.size(); i++) {
				dataDisks.put("DataDisk." + (i + 1) + ".Type", dataDiskArray.get(i).getString("type"));
				dataDisks.put("DataDisk." + (i + 1) + ".Size", dataDiskArray.get(i).getInteger("size"));
			}
		}
		model.setDataDisks(dataDisks.toJSONString());
		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 = "CREATE";
		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(model.getDisk());
			cloudServer.setMemory(server.getMemory());
			cloudServer.setCpu(server.getCpu());
			cloudServer.setGmtVmCreate(server.getGmtVmCreate());
			cloudServer.setManagerIp(server.getManagerIp());
			cloudServer.setPrivateIps(server.getPrivateIps());
			cloudServer.setManagerIp(server.getPrivateIps());
			cloudServer.setPublicIps(server.getPublicIps());
			cloudServer.setDisk(server.getDisk());
			cloudServer.setFlavorUuid(server.getFlavorUuid());
			cloudServer.setOsName(server.getOsName());
			cloudServer.setRegionId(server.getRegionId());
			cloudServer.setNetworkUuid(server.getVpcUuid());
			cloudServer.setSubnetUuid(server.getVSwitchId());
			cloudServer.setZone(server.getZone());
			cloudServer.setPswd(model.getPassword());
			String imageUuid = server.getImageUuid();
			cloudServer.setImageUuid(imageUuid);
			if (null != imageUuid && !"".equals(imageUuid)) {
				Image image = imageRepository.getByImageUuid(imageUuid);
				cloudServer.setOsCategory(image.getOsCategory());
				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);
			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 ("system".equals(volume.getType())) {
						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 = server.getSecurityGroups() == null ? new ArrayList<String>()
					: server.getSecurityGroups();
			for (String securityGroup : securityGroups) {
				SecurityGroup group = securityGroupRepository.getByGroupId(securityGroup);
				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));
				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));
				resourceRepository.update(resource);
			}
		} else {
			event = new ResourceEvent(cloudServer.getId(), handler, "失败", userId, new Date(), "VM", vendor.getId(),
					context.getCatalog());
			cloudServerRepository.remove(cloudServer.getId(), userId);
		}
		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)) {
			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);
				}
			}
		}
	}

}
