package com.bocloud.ims.service.resource.h3c;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.common.LocationDriver;
import com.bocloud.cmp.driver.common.TaskMsgDriver;
import com.bocloud.cmp.driver.compute.ClusterDriver;
import com.bocloud.cmp.driver.compute.HostDriver;
import com.bocloud.cmp.driver.compute.HostPoolDriver;
import com.bocloud.cmp.entity.enums.BocloudStatus;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.model.ClusterModel;
import com.bocloud.cmp.model.HostModel;
import com.bocloud.cmp.model.HostOperateModel;
import com.bocloud.cmp.model.VDCModel;
import com.bocloud.cmp.model.h3c.H3cTaskMsgModel;
import com.bocloud.cmp.model.h3c.entity.RsTaskMsg;
import com.bocloud.common.encrypt.AESEncrptor;
import com.bocloud.common.encrypt.Encryptor;
import com.bocloud.common.enums.BoCloudService;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.OperateResult;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.common.MathUtils;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.Cluster;
import com.bocloud.ims.entity.resource.Network;
import com.bocloud.ims.entity.resource.NetworkHost;
import com.bocloud.ims.entity.resource.Server;
import com.bocloud.ims.entity.resource.ServerConfig;
import com.bocloud.ims.entity.resource.Vdc;
import com.bocloud.ims.interfaces.h3c.H3cHostService;
import com.bocloud.ims.interfaces.resource.ServerService;
import com.bocloud.ims.repository.resource.CloudServerRepository;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.ClusterNodeRepository;
import com.bocloud.ims.repository.resource.ClusterRepository;
import com.bocloud.ims.repository.resource.DataStoreFileRepository;
import com.bocloud.ims.repository.resource.DataStoreRepository;
import com.bocloud.ims.repository.resource.ImageRepository;
import com.bocloud.ims.repository.resource.IpPoolRepository;
import com.bocloud.ims.repository.resource.IpRepository;
import com.bocloud.ims.repository.resource.NetworkCardRepository;
import com.bocloud.ims.repository.resource.NetworkHostRepository;
import com.bocloud.ims.repository.resource.NetworkRepository;
import com.bocloud.ims.repository.resource.PortGroupRepository;
import com.bocloud.ims.repository.resource.ResourceRepository;
import com.bocloud.ims.repository.resource.ServerAssetsRepository;
import com.bocloud.ims.repository.resource.ServerConfigRepository;
import com.bocloud.ims.repository.resource.ServerRepository;
import com.bocloud.ims.repository.resource.SnapshotRepository;
import com.bocloud.ims.repository.resource.StoreHostRepository;
import com.bocloud.ims.repository.resource.SwitcherRepository;
import com.bocloud.ims.repository.resource.VdcRepository;
import com.bocloud.ims.repository.resource.VolumeRepository;
import com.bocloud.ims.service.model.cmdb.CmdbInfo;
import com.bocloud.ims.service.transportor.H3cTransportor;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.ims.service.utils.SyncH3cUtils;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service("h3cHostService")
public class H3cHostServiceImpl extends H3cCommonService implements H3cHostService {

	@Autowired
	CloudVendorRepository cloudVendorRepository;
	@Autowired
	ServerRepository serverRepository;
	@Autowired
	VdcRepository vdcRepository;
	@Autowired
	HostDriver hostDriver;
	@Autowired
	IpRepository ipRepository;
	@Autowired
	CloudServerRepository cloudServerRepository;
	@Autowired
	DataStoreRepository dataStoreRepository;
	@Autowired
	SnapshotRepository snapshotRepository;
	@Autowired
	NetworkRepository networkRepository;
	@Autowired
	StoreHostRepository storeHostRepository;
	@Autowired
	NetworkCardRepository networkCardRepository;
	@Autowired
	PortGroupRepository portGroupRepository;
	@Autowired
	NetworkHostRepository networkHostRepository;
	@Autowired
	ServerConfigRepository serverConfigRepository;
	@Autowired
	ResourceRepository resourceRepository;
	@Autowired
	ImageRepository imageRepository;
	@Autowired
	ClusterRepository clusterRepository;
	@Autowired
	VolumeRepository volumeRepository;
	@Autowired
	ResourceEventPublisher resourceEventPublisher;
	@Autowired
	SwitcherRepository switcherRepository;
	@Autowired
	DataStoreFileRepository dataStoreFileRepository;
	@Autowired
	LockFactory lockFactory;
	@Autowired
	TaskMsgDriver taskMsgDriver;
	@Autowired
	LocationDriver locationDriver;
	@Autowired
	@Qualifier("ServerService")
	ServerService serverService;
	@Autowired
	HostPoolDriver hostPoolDriver;
	@Autowired
	ClusterDriver clusterDriver;
	@Autowired
	ServerAssetsRepository serverAssetsRepository;
	@Autowired
	ClusterNodeRepository clusterNodeRepository;
	@Autowired
	IpPoolRepository ipPoolRepository;
	@Autowired
	private H3cTransportor h3cTransportor;

	private static OperateResult.OperateCategory operateCategory = OperateResult.OperateCategory.ResourceEvent;

	Logger logger = LoggerFactory.getLogger(this.getClass());

	@Override
	public BocloudResult<String> create(HostOperateModel model, RequestContext context) {
		try {
			Encryptor encryptor = new AESEncrptor();
			model.setPassword(encryptor.decrypt(model.getPassword(), null));
			Long userId = context.getTarget();
			Long vendorId = model.getVendorId();
			CloudVendor vendor = cloudVendorRepository.query(vendorId);
			if (null == vendor) {
				return new BocloudResult<String>(false, "获取云供应商失败");
			}
			Vdc vdc = vdcRepository.query(model.getVdcId());
			if (null == vdc) {
				return new BocloudResult<String>(false, "虚拟数据中心不存在");
			}
			Cluster cluster = clusterRepository.query(model.getClusterId());
			Server detail = serverService.detail(model.getHostIp());
			if (detail != null) {
				return new BocloudResult<String>(false, "该主机已存在,无法添加");
			}
			// 启动一个线程
			CloudVendor finalVendor = vendor;
			Vdc finalVdc = vdc;
			new Thread(new Runnable() {
				@SuppressWarnings("unchecked")
				@Override
				public void run() {
					HostOperateModel modelForRemoteCreate = new HostOperateModel();
					BeanUtils.copyProperties(model, modelForRemoteCreate);
					modelForRemoteCreate.setVdcId(Long.valueOf(finalVdc.getVdcVal()));
					if (cluster != null) {
						modelForRemoteCreate.setClusterId(Long.valueOf(cluster.getClusterVal()));
					}
					BocloudResult result = hostDriver.create(finalVendor.getUuid(), null, modelForRemoteCreate);
					String type = finalVendor.getType();
					String operate = type.toLowerCase() + ".host";
					if (result.isSuccess() && null != result.getData()) {
						try {
							String content = JSONObject.toJSONString(result.getData());
							RsTaskMsg msgModel = JSONObject.parseObject(content, RsTaskMsg.class);
							// 需要调用查询所有主机,然后按主机的ip找到对应主机

							BocloudResult<List<HostModel>> hostListResult;
							if (cluster != null) {
								hostListResult = hostDriver.list(finalVendor.getUuid(), null, cluster.getClusterVal());
							} else {
								hostListResult = hostDriver.list(finalVendor.getUuid(), null);
							}
							@SuppressWarnings("unchecked")
							List<HostModel> hostModels = (List<HostModel>) hostListResult.getData();
							Map<String, Cluster> clusterMap = new HashMap<String, Cluster>();
							clusterMap.put(cluster.getClusterVal(), cluster);
							Map<String, Vdc> vdcMap = new HashMap<String, Vdc>();
							vdcMap.put(finalVdc.getVdcVal(), finalVdc);
							h3cTransportor.syncHost(hostModels, finalVendor, userId, clusterMap, vdcMap);
							// 更新vdc的信息
							BocloudResult summary = hostPoolDriver.summary(finalVendor.getUuid(), finalVdc.getVdcVal());
							VDCModel vdcModel = (VDCModel) summary.getData();
							updateVdc(vdcModel, finalVdc);
							// 更新cluster信息
							if (cluster != null) {
								BocloudResult clusterSummary = clusterDriver.summary(finalVendor.getUuid(),
										cluster.getClusterVal());
								ClusterModel clusterModel = (ClusterModel) clusterSummary.getData();
								updateClusterModel(clusterModel, cluster);
							}
							sendMessage(true, userId, finalVendor, operate, "添加宿主机成功", operateCategory);
						} catch (Exception e) {
							logger.error("Create host fail:", e);
							sendMessage(false, userId, finalVendor, operate, "添加宿主机失败", operateCategory);
							return;
						}
					} else {
						sendMessage(false, userId, finalVendor, operate, "添加宿主机失败", operateCategory);
					}
				}
			}).start();
			return new BocloudResult<String>(true, "添加任务已经下发，正在执行……");
		} catch (Exception e) {
			logger.error("Create host fail:", e);
			return new BocloudResult<String>(false, "添加失败");
		}

	}

	private void updateClusterModel(ClusterModel clusterModel, Cluster cluster) throws Exception {
		cluster.setCpuTotal(clusterModel.getCpuTotal());
		if (clusterModel.getDiskTotal() != null) {
			cluster.setDiskTotal(clusterModel.getDiskTotal());
		}
		if (clusterModel.getDiskUsed() != null) {
			cluster.setDiskUsed(clusterModel.getDiskUsed());
		}
		cluster.setMemTotal(cluster.getMemTotal());
		clusterRepository.update(cluster);
	}

	@Override
	public BocloudResult remove(Long id, RequestContext context, Server host, CloudVendor vendor) {
		try {
			if (null == host) {
				host = this.serverRepository.query(id);
			}
			if (null == host) {
				logger.warn("Server data does not exist!");
				return new BocloudResult(false, "主机不存在");
			}
			Vdc vdc = vdcRepository.query(host.getVdcId());
			if (null == vendor) {
				vendor = cloudVendorRepository.query(host.getVendorId());
			}
			if (null == vendor) {
				return new BocloudResult(false, "获取云供应商失败");
			}
			List<NetworkHost> nHosts = networkHostRepository.list(id, "PM");
			for (NetworkHost nHost : nHosts) {
				Network network = networkRepository.query(nHost.getNetworkId());
				if (null == network) {
					continue;
				}
			}
			Server finalHost = host;
			CloudVendor finalVendor = vendor;
			Vdc finalVdc = vdc;
			new Thread(() -> {
				String uuid = finalHost.getUuid();
				// 移除宿主机
				HostOperateModel model = new HostOperateModel();
				model.setHostName(finalHost.getName());
				model.setClusterName(finalHost.getClusterName());
				// 华三云uuid是数字，vCenter的uuid不是数字
				if (CloudProvider.H3C.name().equals(finalVendor.getType()) && MathUtils.isLong(uuid)) {
					model.setHostId(Long.valueOf(uuid));
				}
				BocloudResult result = hostDriver.remove(finalVendor.getUuid(), null, model);
				String type = finalVendor.getType();
				String operate = type.toLowerCase() + ".host";
				if (result.isSuccess()) {
					try {
						String content = JSONObject.toJSONString(result.getData());
						H3cTaskMsgModel msgModel = JSONObject.parseObject(content, H3cTaskMsgModel.class);
						Long msgId = msgModel.getMsgId();
						long start = System.currentTimeMillis();
						Long timeout = 60000L;
						BocloudResult<H3cTaskMsgModel> taskResult = null;
						try {
							taskResult = queryTaskResult(finalVendor, msgId, start, timeout);
						} catch (InterruptedException e) {
							logger.error("查询结果出错", e);
							Thread.currentThread().interrupt();
						}
						boolean isSuccess = null == taskResult ? false : taskResult.isSuccess();
						if (!isSuccess) {
							resourceEventPublisher.send(new OperateResult(false, "删除宿主机失败", operate,
									MapTools.simpleMap("vendorId", finalVendor.getId()),
									OperateResult.OperateCategory.ResourceEvent, context));
							return;
						}
						SyncH3cUtils syncH3cUtils = new SyncH3cUtils(cloudServerRepository, serverRepository,
								snapshotRepository, dataStoreRepository, networkRepository, clusterRepository,
								storeHostRepository, networkCardRepository, networkHostRepository,
								serverConfigRepository, resourceRepository, ipRepository, imageRepository,
								volumeRepository, dataStoreFileRepository, switcherRepository, vdcRepository);

						// 同步到cmdb
						List<CmdbInfo> infos = Lists.newArrayList();
						syncH3cUtils.removeHostCascade(finalHost, context.getTarget(), infos);
						if (null != finalHost.getClusterId()) {
							clusterNodeRepository.removeByRid(finalHost.getResourceId(), context.getTarget());
							Cluster cluster = clusterRepository.query(finalHost.getClusterId());
							if (cluster != null) {
								BocloudResult clusterSummary = clusterDriver.summary(finalVendor.getUuid(),
										cluster.getClusterVal());
								ClusterModel clusterModel = (ClusterModel) clusterSummary.getData();
								updateClusterModel(clusterModel, cluster);
							}
						}
						BocloudResult summary = hostPoolDriver.summary(finalVendor.getUuid(), finalVdc.getVdcVal());
						VDCModel vdcModel = (VDCModel) summary.getData();
						updateVdc(vdcModel, finalVdc);

					} catch (Exception e) {
						logger.error("删除失败", e);
						resourceEventPublisher.send(new OperateResult(false, "删除宿主机失败", operate,
								MapTools.simpleMap("vendorId", finalVendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
						return;
					}
				}
				resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(), operate,
						MapTools.simpleMap("vendorId", finalVendor.getId()),
						OperateResult.OperateCategory.ResourceEvent, context));
			}).start();
			return new BocloudResult(true, "删除任务已下发，正在执行...");
		} catch (Exception e) {
			logger.error("Remove server fail:", e);
			return new BocloudResult(false, "删除失败");
		}
	}

	@Override
	public BocloudResult shutdown(HostOperateModel model, Long userId, Server server, ServerConfig config,
			CloudVendor vendor) {
		try {
			Long vendorId = model.getVendorId();
			if (null == vendor) {
				vendor = cloudVendorRepository.query(vendorId);
			}
			if (null == vendor) {
				return new BocloudResult(false, "获取云供应商失败");
			}
			// 启动一个线程
			CloudVendor finalVendor = vendor;
			new Thread(() -> {
				HostOperateModel modelForRemoteCreate = new HostOperateModel();
				BeanUtils.copyProperties(model, modelForRemoteCreate);
				BocloudResult result = hostDriver.shutdown(finalVendor.getUuid(), null, modelForRemoteCreate);
				String type = finalVendor.getType();
				String operate = type.toLowerCase() + ".host";
				if (result.isSuccess() && null != result.getData()) {
					try {
						String content = JSONObject.toJSONString(result.getData());
						H3cTaskMsgModel msgModel = JSONObject.parseObject(content, H3cTaskMsgModel.class);
						Long msgId = msgModel.getMsgId();
						long start = System.currentTimeMillis();
						Long timeout = 60000L;
						BocloudResult<H3cTaskMsgModel> taskResult = queryTaskResult(finalVendor, msgId, start, timeout);
						boolean isSuccess = taskResult.isSuccess();
						if (isSuccess) {
							server.setStatus(BocloudStatus.Server.STOPPED.name());
							server.setPowerState(BocloudStatus.Server.STOPPED.name());
							serverRepository.update(server);
							sendMessage(true, userId, finalVendor, operate, "关闭宿主机成功", operateCategory);
						} else {
							sendMessage(false, userId, finalVendor, operate, "关闭宿主机失败", operateCategory);
						}
					} catch (Exception e) {
						logger.error("Create host fail:", e);
						sendMessage(false, userId, finalVendor, operate, "关闭宿主机失败", operateCategory);
						return;
					}
				} else {
					sendMessage(false, userId, finalVendor, operate, "关闭宿主机失败", operateCategory);
				}
			}).start();
			return new BocloudResult(true, "关闭任务已经下发，正在执行……");
		} catch (Exception e) {
			logger.error("Create host fail:", e);
			return new BocloudResult(false, "关闭失败");
		}

	}

	@Override
	public BocloudResult enterMode(HostOperateModel model, Long userId, Server server, CloudVendor vendor) {
		try {
			Long vendorId = model.getVendorId();
			if (null == vendor) {
				vendor = cloudVendorRepository.query(vendorId);
			}
			if (null == vendor) {
				return new BocloudResult(false, "获取云供应商失败");
			}
			// 启动一个线程
			CloudVendor finalVendor = vendor;
			new Thread(() -> {
				HostOperateModel modelForRemoteCreate = new HostOperateModel();
				BeanUtils.copyProperties(model, modelForRemoteCreate);
				BocloudResult result = hostDriver.enterMode(finalVendor.getUuid(), null, modelForRemoteCreate);
				String type = finalVendor.getType();
				String operate = type.toLowerCase() + ".host";
				if (result.isSuccess() && null != result.getData()) {
					try {
						String content = JSONObject.toJSONString(result.getData());
						H3cTaskMsgModel msgModel = JSONObject.parseObject(content, H3cTaskMsgModel.class);
						Long msgId = msgModel.getMsgId();
						long start = System.currentTimeMillis();
						Long timeout = 60000L;
						BocloudResult<H3cTaskMsgModel> taskResult = queryTaskResult(finalVendor, msgId, start, timeout);
						boolean isSuccess = taskResult.isSuccess();
						if (isSuccess) {
							server.setMaintained(true);
							server.setMenderId(userId);
							this.serverRepository.update(server);
							sendMessage(true, userId, finalVendor, operate, "宿主机进入维护模式成功", operateCategory);
						} else {
							sendMessage(false, userId, finalVendor, operate, "宿主机进入维护模式失败", operateCategory);
						}
					} catch (Exception e) {
						logger.error("Create host fail:", e);
						sendMessage(false, userId, finalVendor, operate, "宿主机进入维护模式失败", operateCategory);
						return;
					}
				} else {
					sendMessage(false, userId, finalVendor, operate, "宿主机进入维护模式失败", operateCategory);
				}
			}).start();
			return new BocloudResult(true, "进入维护模式任务已经下发，正在执行……");
		} catch (Exception e) {
			logger.error("Create host fail:", e);
			return new BocloudResult(false, "宿主机进入维护模式失败");
		}
	}

	@Override
	public BocloudResult exitMode(HostOperateModel model, Long userId, Server server, CloudVendor vendor) {
		try {
			Long vendorId = model.getVendorId();
			if (null == vendor) {
				vendor = cloudVendorRepository.query(vendorId);
			}
			if (null == vendor) {
				return new BocloudResult(false, "获取云供应商失败");
			}
			// 启动一个线程
			CloudVendor finalVendor = vendor;
			new Thread(() -> {
				HostOperateModel modelForRemoteCreate = new HostOperateModel();
				BeanUtils.copyProperties(model, modelForRemoteCreate);
				BocloudResult result = hostDriver.exitMode(finalVendor.getUuid(), null, modelForRemoteCreate);
				String type = finalVendor.getType();
				String operate = type.toLowerCase() + ".host";
				if (result.isSuccess() && null != result.getData()) {
					try {
						String content = JSONObject.toJSONString(result.getData());
						H3cTaskMsgModel msgModel = JSONObject.parseObject(content, H3cTaskMsgModel.class);
						Long msgId = msgModel.getMsgId();
						long start = System.currentTimeMillis();
						Long timeout = 60000L;
						BocloudResult<H3cTaskMsgModel> taskResult = queryTaskResult(finalVendor, msgId, start, timeout);
						boolean isSuccess = taskResult.isSuccess();
						if (isSuccess) {
							server.setMaintained(false);
							server.setMenderId(userId);
							this.serverRepository.update(server);
							sendMessage(true, userId, finalVendor, operate, "宿主机退出维护模式成功", operateCategory);
						} else {
							sendMessage(false, userId, finalVendor, operate, "宿主机退出维护模式失败", operateCategory);
						}
					} catch (Exception e) {
						logger.error("Create host fail:", e);
						sendMessage(false, userId, finalVendor, operate, "宿主机退出维护模式失败", operateCategory);
						return;
					}
				} else {
					sendMessage(false, userId, finalVendor, operate, "宿主机退出维护模式失败", operateCategory);
				}
			}).start();
			return new BocloudResult(true, "退出维护模式任务已经下发，正在执行……");
		} catch (Exception e) {
			logger.error("Create host fail:", e);
			return new BocloudResult(false, "宿主机退出维护模式失败");
		}
	}

	public void updateVdc(VDCModel vdcModel, Vdc finalVdc) throws Exception {
		finalVdc.setCpuTotal(vdcModel.getCpuTotal());
		if (vdcModel.getDiskTotal() != null) {
			finalVdc.setDiskTotal(vdcModel.getDiskTotal());
		}
		if (vdcModel.getDiskUsed() != null) {
			finalVdc.setDiskUsed(vdcModel.getDiskUsed());
		}
		finalVdc.setMemTotal(vdcModel.getMemTotal());
		finalVdc.setType(CloudProvider.H3C.name());
		vdcRepository.update(finalVdc);
	}

	private HostModel findHostModelByIp(List<HostModel> hostModels, String ip) {
		HostModel model = new HostModel();
		if (!ListTool.isEmpty(hostModels)) {
			for (HostModel hostModel : hostModels) {
				if (ip.equals(hostModel.getHostIp())) {
					model = hostModel;
					break;
				}
			}
		}
		return model;
	}

	@Override
	protected ResourceEventPublisher getResourceEventPublisher() {
		return this.resourceEventPublisher;
	}

	@Override
	protected TaskMsgDriver getTaskMsgDriver() {
		return this.taskMsgDriver;
	}
}
