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

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.kubernetes.NodeDriver;
import com.bocloud.cmp.model.kubernetes.NodeModel;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.OperateResult;
import com.bocloud.common.model.Pager;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.kubernetes.KubeNode;
import com.bocloud.ims.entity.resource.kubernetes.KubeNodeLabel;
import com.bocloud.ims.interfaces.resource.kubernetes.KubeNodeLabelService;
import com.bocloud.ims.repository.kubernetes.KubeNodeLabelRepository;
import com.bocloud.ims.repository.kubernetes.KubeNodeRepository;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Maps;

@Service("kubeNodeLabelService")
public class KubeNodeLabelServiceImpl implements KubeNodeLabelService {

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

	@Autowired
	private KubeNodeLabelRepository kubeNodeLabelRepository;
	@Autowired
	private LockFactory lockFactory;
	@Autowired
	private CloudVendorRepository cloudVendorRepository;
	@Autowired
	private NodeDriver nodeDriver;
	@Autowired
	private KubeNodeRepository kubeNodeRepository;
	@Autowired
	private ResourceEventPublisher resourceEventPublisher;

	@Override
	public BocloudResult list(Pager pager) {
		List<KubeNodeLabel> list = null;
		int total = 0;
		GridBean gridBean = null;
		try {
			List<Param> params = Optional.ofNullable(pager.getParams()).orElse(new ArrayList<>());
			Map<String, String> sorter = Optional.ofNullable(pager.getSorter()).orElse(Maps.newHashMap());
			Boolean simple = Optional.ofNullable(pager.getSimple()).orElse(false);
			sorter.put("gmtCreate", Common.ONE);
			Integer page = Optional.ofNullable(pager.getPage()).orElse(1);
			Integer rows = Optional.ofNullable(pager.getRows()).orElse(10);

			total = kubeNodeLabelRepository.count(params);
			if (simple) {
				List<KubeNodeLabel> beans = this.kubeNodeLabelRepository.list(params);
				gridBean = new GridBean(1, 1, total, beans);
			} else {
				list = kubeNodeLabelRepository.list(page, rows, params, sorter);
				if (!ListTool.isEmpty(list)) {
					for (KubeNodeLabel kubeNodeLabel : list) {
						String nodeNames = kubeNodeLabel.getNodeNames();
						if (!StringUtils.isEmpty(nodeNames)) {
							nodeNames = nodeNames.substring(1, nodeNames.length() - 1);
							kubeNodeLabel.setNodeNames(nodeNames);
						}
					}
				}
				gridBean = GridHelper.getBean(page, rows, total, list);
			}
			return new BocloudResult(true, gridBean, "查询成功");
		} catch (Exception e) {
			logger.error("list label failure:", e);
			return new BocloudResult(false, "查询失败");
		}
	}

	@Override
	public BocloudResult detail(Long id) {
		try {
			KubeNodeLabel label = kubeNodeLabelRepository.query(id);
			return new BocloudResult(true, label, "查询成功");
		} catch (Exception e) {
			logger.error("Get error message：", e);
			return new BocloudResult(false, "查询失败");
		}
	}

	@Override
	public BocloudResult create(KubeNodeLabel label) {
		try {
			if (kubeNodeLabelRepository.exists(label.getName(), label.getVendorId())) {
				return new BocloudResult(false, "名称已存在");
			}
			Long vendorId = label.getVendorId();
			CloudVendor cloudVendor = cloudVendorRepository.query(vendorId);
			if (null == cloudVendor) {
				return new BocloudResult(false, "集群信息异常！");
			}
			String nodeIds = label.getNodeIds();
			if (StringUtils.isEmpty(nodeIds)) {
				return new BocloudResult(false, "请选择节点数据！");
			}
			List<Long> nodeIdsArray = JSONObject.parseArray(nodeIds, Long.class);
			for (Long nodeId : nodeIdsArray) {
				KubeNode kubeNode = kubeNodeRepository.query(nodeId);
				if (null == kubeNode) {
					return new BocloudResult(false, "节点数据异常！");
				}
				NodeModel model = new NodeModel();
				JSONObject object = new JSONObject();
				object.put("key", label.getName());
				object.put("value", label.getContent());
				model.setLabels(object.toJSONString());
				model.setName(kubeNode.getName());
				BocloudResult bocloudResult = nodeDriver.addNodeLabels(cloudVendor.getUuid(), model);
				if (bocloudResult.isFailed()) {
					return bocloudResult;
				}
			}
			kubeNodeLabelRepository.save(label);
			return new BocloudResult(true, label, "添加成功");
		} catch (Exception e) {
			logger.error("Create label error:", e);
			return new BocloudResult(false, "添加失败");
		}
	}

	@Override
	public BocloudResult modify(KubeNodeLabel kubeNodeLabel, RequestContext context) {
		String path = KubeNodeLabel.class.getSimpleName() + "_" + kubeNodeLabel.getId();
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			KubeNodeLabel oldLabel = this.kubeNodeLabelRepository.query(kubeNodeLabel.getId());
			if (null == oldLabel) {
				logger.warn("Label does not exist!");
				return new BocloudResult(false, "数据不存在");
			}
			CloudVendor cloudVendor = cloudVendorRepository.query(oldLabel.getVendorId());
			if (null == cloudVendor) {
				return new BocloudResult(false, "集群信息异常！");
			}
			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						String oldNodeIds = oldLabel.getNodeIds();
						List<Long> oldNodeIdsArray = JSONObject.parseArray(oldNodeIds, Long.class);
						if (!ListTool.isEmpty(oldNodeIdsArray)) {
							for (Long nodeId : oldNodeIdsArray) {
								KubeNode kubeNode = kubeNodeRepository.query(nodeId);
								if (null == kubeNode) {
									resourceEventPublisher
											.send(new OperateResult(false, "标签修改失败！", "kubernetes.nodeLabels",
													MapTools.simpleMap(Common.VENDORID, cloudVendor.getId()),
													OperateResult.OperateCategory.ResourceEvent, context));
									return;
								}
								NodeModel model = new NodeModel();
								model.setLabelKey(oldLabel.getName());
								model.setName(kubeNode.getName());
								BocloudResult removeNodeLabels = nodeDriver.removeNodeLabels(cloudVendor.getUuid(),
										model);
								if (removeNodeLabels.isFailed()) {
									resourceEventPublisher
											.send(new OperateResult(false, "标签修改失败！", "kubernetes.nodeLabels",
													MapTools.simpleMap(Common.VENDORID, cloudVendor.getId()),
													OperateResult.OperateCategory.ResourceEvent, context));
									return;
								}
								NodeModel nodeModel = JSON.parseObject(JSON.toJSONString(removeNodeLabels.getData()),
										NodeModel.class);
								kubeNode.setLabels(nodeModel.getLabels());
								kubeNodeRepository.update(kubeNode);
							}
						}
						String newNodeIds = kubeNodeLabel.getNodeIds();
						List<Long> newNodeIdsArray = JSONObject.parseArray(newNodeIds, Long.class);
						if (!ListTool.isEmpty(newNodeIdsArray)) {
							JSONObject object = new JSONObject();
							object.put("key", oldLabel.getName());
							object.put("value", kubeNodeLabel.getContent());
							BocloudResult modifyNodeLabels = modifyNodeLabels(newNodeIdsArray, object, cloudVendor);
							if (modifyNodeLabels.isFailed()) {
								resourceEventPublisher.send(new OperateResult(false, "标签修改失败！", "kubernetes.nodeLabels",
										MapTools.simpleMap(Common.VENDORID, cloudVendor.getId()),
										OperateResult.OperateCategory.ResourceEvent, context));

								return;
							}
						}
						oldLabel.setNodeIds(kubeNodeLabel.getNodeIds());
						oldLabel.setContent(kubeNodeLabel.getContent());
						oldLabel.setNodeNames(kubeNodeLabel.getNodeNames());
						kubeNodeLabelRepository.update(oldLabel);

						resourceEventPublisher.send(new OperateResult(true, "标签修改成功！", "kubernetes.service",
								MapTools.simpleMap(Common.VENDORID, cloudVendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));

					} catch (Exception e) {
						logger.error("标签修改失败：" + e.getMessage());
						resourceEventPublisher.send(new OperateResult(false, "标签修改失败：" + e.getMessage(),
								"kubernetes.service", MapTools.simpleMap(Common.VENDORID, cloudVendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
					}
				}
			}).start();
			return new BocloudResult(true, "任务已下发，正在执行...");
		} catch (Exception e) {
			logger.error("Modify label error:", e);
			return new BocloudResult(false, "修改失败");
		}
	}

	public BocloudResult modifyNodeLabels(List<Long> oldNodeIdsArray, JSONObject object, CloudVendor cloudVendor) {
		try {
			for (Long nodeId : oldNodeIdsArray) {
				KubeNode kubeNode = kubeNodeRepository.query(nodeId);
				if (null == kubeNode) {
					return new BocloudResult(false, "节点数据异常！");
				}
				NodeModel model = new NodeModel();
				model.setLabels(object.toJSONString());
				model.setName(kubeNode.getName());
				BocloudResult bocloudResult = nodeDriver.addNodeLabels(cloudVendor.getUuid(), model);
				if (bocloudResult.isFailed()) {
					return bocloudResult;
				}
				NodeModel nodeModel = JSON.parseObject(JSON.toJSONString(bocloudResult.getData()), NodeModel.class);
				kubeNode.setLabels(nodeModel.getLabels());
				kubeNodeRepository.update(kubeNode);
			}
			return new BocloudResult(true, "标签修改成功！");
		} catch (Exception e) {
			logger.error("标签修改失败：" + e.getMessage());
			return new BocloudResult(false, "标签修改失败：" + e.getMessage());
		}
	}

	@Override
	public BocloudResult remove(Long id) {
		String path = KubeNodeLabel.class.getSimpleName() + "_" + id;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			KubeNodeLabel oldLabel = this.kubeNodeLabelRepository.query(id);
			if (null == oldLabel) {
				logger.warn("Label does not exist!");
				return new BocloudResult(false, "数据不存在");
			}
			CloudVendor cloudVendor = cloudVendorRepository.query(oldLabel.getVendorId());
			if (null == cloudVendor) {
				return new BocloudResult(false, "集群信息异常！");
			}
			String nodeIds = oldLabel.getNodeIds();
			if (!StringUtils.isEmpty(nodeIds)) {
				List<Long> nodeIdsArray = JSONObject.parseArray(nodeIds, Long.class);
				for (Long nodeId : nodeIdsArray) {
					KubeNode kubeNode = kubeNodeRepository.query(nodeId);
					if (null == kubeNode) {
						return new BocloudResult(false, "节点数据异常！");
					}
					NodeModel model = new NodeModel();
					model.setLabelKey(oldLabel.getName());
					model.setName(kubeNode.getName());
					BocloudResult bocloudResult = nodeDriver.removeNodeLabels(cloudVendor.getUuid(), model);
					if (bocloudResult.isFailed()) {
						return bocloudResult;
					}
				}
			}
			this.kubeNodeLabelRepository.remove(id);
			return new BocloudResult(true, "删除成功");
		} catch (Exception e) {
			logger.error("Remove label error:", e);
			return new BocloudResult(false, "删除失败");
		}
	}
}
