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

import java.util.ArrayList;
import java.util.Date;
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.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.kubernetes.NodeDriver;
import com.bocloud.cmp.model.kubernetes.KubeNodeParam;
import com.bocloud.cmp.model.kubernetes.NodeModel;
import com.bocloud.common.encrypt.AESEncrptor;
import com.bocloud.common.encrypt.Encryptor;
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.model.SimpleBean;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.JSONTools;
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.interfaces.resource.SyncService;
import com.bocloud.ims.interfaces.resource.kubernetes.KubeNodeService;
import com.bocloud.ims.repository.kubernetes.KubeNodeRepository;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.service.internal.worker.RequestWorker;
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("kubeNodeService")
@Scope("prototype")
public class KubeNodeServiceImpl implements KubeNodeService {

	private static final Logger logger = LoggerFactory.getLogger(KubeNodeServiceImpl.class);
	@Autowired
	private CloudVendorRepository cloudVendorRepository;
	@Autowired
	private KubeNodeRepository kubeNodeRepository;
	@Autowired
	private LockFactory lockFactory;
	@Autowired
	private NodeDriver nodeDriver;
	@Autowired
	private RequestWorker requestWorker;
	@Autowired
	private ResourceEventPublisher resourceEventPublisher;
	@Autowired
	private SyncService syncService;

	@Override
	public BocloudResult list(Pager pager) {
		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);

			int total = this.kubeNodeRepository.count(params);
			if (simple) {
				List<SimpleBean> beans = this.kubeNodeRepository.list(params, sorter);
				gridBean = new GridBean(1, 1, total, beans);
			} else {
				List<KubeNode> list = this.kubeNodeRepository.list(page, rows, params, sorter);
				gridBean = GridHelper.getBean(page, rows, total, list);
			}
			return new BocloudResult(true, gridBean, "查询成功");
		} catch (Exception e) {
			logger.error("Query node list fail:", e);
			return new BocloudResult(false, "查询失败");
		}
	}

	@Override
	public BocloudResult create(KubeNode node, RequestContext context) {
		try {
			CloudVendor vendor = cloudVendorRepository.query(node.getVendorId());
			if (null == vendor) {
				return new BocloudResult(false, "获取云供应商失败");
			}
			node.preSave(context.getTarget(), context.getTarget(), vendor.getId());
			this.kubeNodeRepository.save(node);
			return new BocloudResult(true, "添加成功");
		} catch (Exception e) {
			logger.error("create node error", e);
			return new BocloudResult(false, "添加失败");
		}
	}

	@Override
	public BocloudResult modify(KubeNodeParam kubeNodeParam, RequestContext context) {
		if (null == kubeNodeParam) {
			return new BocloudResult(false, "参数格式错误！");
		}
		Long nodeId = kubeNodeParam.getId();
		String path = KubeNode.class.getSimpleName() + "_" + nodeId;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			JSONArray jsonArray = kubeNodeParam.getLabels();
			if (jsonArray.size() <= 0) {
				return new BocloudResult(false, "请设置标签信息！");
			}
			KubeNode kubeNode = this.kubeNodeRepository.query(nodeId);
			if (null == kubeNode) {
				logger.warn("node does not exist!");
				return new BocloudResult(false, "节点数据不存在");
			}
			CloudVendor cloudVendor = cloudVendorRepository.query(kubeNode.getVendorId());
			if (null == cloudVendor) {
				return new BocloudResult(false, "集群信息异常！");
			}

			NodeModel model = new NodeModel();
			model.setLabels(jsonArray.toJSONString());
			model.setName(kubeNode.getName());
			BocloudResult bocloudResult = nodeDriver.modify(cloudVendor.getUuid(), model);
			NodeModel nodeModel = JSONObject.parseObject(JSON.toJSONString(bocloudResult.getData()), NodeModel.class);
			kubeNode.setLabels(nodeModel.getLabels());
			kubeNode.setMenderId(context.getTarget());
			this.kubeNodeRepository.update(kubeNode);
			return new BocloudResult(true, "标签设置成功");
		} catch (Exception e) {
			logger.error("Modify node label fail:", e);
			return new BocloudResult(false, "标签设置失败");
		}
	}

	@Override
	public BocloudResult remove(Long id, RequestContext context) {
		String path = KubeNode.class.getSimpleName() + "_" + id;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			KubeNode node = this.kubeNodeRepository.query(id);
			if (null == node) {
				return new BocloudResult(false, "数据不存在");
			}
			CloudVendor vendor = cloudVendorRepository.query(node.getVendorId());
			if (null == vendor) {
				return new BocloudResult(false, "获取云供应商失败");
			}
			this.kubeNodeRepository.remove(id, context.getTarget());
			return new BocloudResult(true, "删除成功");
		} catch (Exception e) {
			logger.error("Remove node error:", e);
			return new BocloudResult(false, "删除失败");
		}
	}

	@Override
	public BocloudResult detail(Long id) {
		try {
			KubeNode node = this.kubeNodeRepository.query(id);
			if (null == node) {
				return new BocloudResult(false, "数据不存在");
			}
			return new BocloudResult(true, node, "查询详情成功");
		} catch (Exception e) {
			logger.error("Get node error：", e);
			return new BocloudResult(false, "查询详情失败");
		}
	}

	@Override
	public BocloudResult schedule(Long id, RequestContext context) {
		String path = KubeNode.class.getSimpleName() + "_" + id;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			KubeNode node = this.kubeNodeRepository.query(id);
			if (null == node) {
				logger.warn("node does not exist!");
				return new BocloudResult(false, "数据不存在");
			}
			CloudVendor cloudVendor = cloudVendorRepository.query(node.getVendorId());
			if (null == cloudVendor) {
				return new BocloudResult(false, "云平台不存在！");
			}
			NodeModel model = new NodeModel();
			BeanUtils.copyProperties(node, model);
			model.setSchedulable(!node.getSchedulable());
			BocloudResult result = nodeDriver.modifySchedule(cloudVendor.getUuid(), model);
			if (result.isFailed()) {
				return new BocloudResult(false, "调度策略调整失败：" + result.getMessage());
			}
			node.setSchedulable(model.getSchedulable());
			node.setGmtModify(new Date());
			node.setMenderId(context.getTarget());
			this.kubeNodeRepository.update(node);
			return new BocloudResult(true, model.getSchedulable() ? "调度策略启用成功" : "调度策略禁用成功");
		} catch (Exception e) {
			logger.error("set node schedule fail:", e);
			return new BocloudResult(true, "禁用调度失败：" + e.getMessage());
		}
	}

	/**
	 * 192.168.2.80 为deploy节点的ip地址，用户名为root，密码为Passw0rd 192.168.2.84
	 * 为需要新增节点的ip地址，用户名为root，密码为Passw0rd
	 * 
	 * @param params
	 * @param context
	 * @return
	 */
	@Override
	public BocloudResult operation(String params, RequestContext context) {
		JSONObject object = JSONTools.isJSONObj(params);
		if (null == object) {
			return new BocloudResult(false, "参数格式错误！");
		}
		try {
			Long vendorId = object.getLong(Common.VENDORID);
			CloudVendor cloudVendor = cloudVendorRepository.query(vendorId);
			if (null == cloudVendor) {
				return new BocloudResult(false, "集群信息异常");
			}
			if (StringUtils.isEmpty(cloudVendor.getDeployUrl()) || StringUtils.isEmpty(cloudVendor.getDeployUsername())
					|| StringUtils.isEmpty(cloudVendor.getDeployPassword())) {
				return new BocloudResult(false, "部署机信息为空！");
			}
			/**
			 * String nodeIp = "192.168.2.84"; String nodeUser = "root"; String nodePwd =
			 * "Passw0rd";
			 */
			String action = object.getString(Common.ACTION); // add-node添加
																// del-node
			if (StringUtils.isEmpty(action)) {
				return new BocloudResult(false, "无效的操作类型！");
			}
			logger.info("action : " + action);
			String nodeIp = object.getString("nodeIp");
			String nodeUser = object.getString("nodeUser");
			Integer nodePort = object.getInteger("nodePort") == null ? 22 : object.getInteger("nodePort");
			String nodePwd = object.getString("nodePwd");
			if (StringUtils.isEmpty(nodeIp) || StringUtils.isEmpty(nodeUser) || StringUtils.isEmpty(nodePwd)) {
				return new BocloudResult(false, "缺少必要参数！");
			}
			Encryptor encryptor = new AESEncrptor();
			nodePwd = encryptor.decrypt(nodePwd, null);
			this.setWorkerCallBack(new WorkerCallBack(cloudVendor, context.getTarget(), Boolean.TRUE, action, nodeIp));
			return deployLogin(cloudVendor, nodeIp, nodeUser, nodePwd, nodePort);
		} catch (Exception e) {
			logger.error("添加节点失败: " + e);
			return new BocloudResult(false, "添加节点失败:" + e.getMessage());
		}
	}

	public BocloudResult handleNode(CloudVendor cloudVendor, String operate, String nodeIp) {
		try {
//			Map<String, Object> paramMap = new HashMap<>();
//			paramMap.put("timeout", 9600);
//			paramMap.put("targets", buildTargets(cloudVendor));
//			String command = " /etc/ansible/tools/easzctl " + operate + " " + nodeIp; // add-node
//			JSONObject module = new JSONObject();
//			module.put("name", "raw");
//			module.put("args", command);
//			paramMap.put("module", module);
//			return requestWorker.invoke(paramMap, this::notify, null);
			return new BocloudResult<>(false, "暂未开发");
		} catch (Exception e) {
			logger.error("添加节点免登陆异常：" + e.getMessage());
			return new BocloudResult(false, "添加节点免登陆异常：" + e.getMessage());
		}
	}

	public BocloudResult deployLogin(CloudVendor cloudVendor, String nodeIp, String nodeUser, String nodePwd,
			Integer nodePort) {
		try {
//			// 做免密
//			Map<String, Object> paramMap = new HashMap<String, Object>();
//			paramMap.put("timeout", 1200);
//			paramMap.put("targets", buildTargets(cloudVendor));
//			String command = "rm -f /etc/ansible/cmphosts; " + " echo " + nodeIp + " ansible_ssh_user=" + nodeUser
//					+ " ansible_ssh_pass=" + nodePwd + " ansible_ssh_port=" + nodePort + " "
//					+ " connection=smart> /etc/ansible/cmphosts; " + " ansible all -i  /etc/ansible/cmphosts -m "
//					+ " authorized_key -a \"user=" + nodeUser
//					+ "  key={{ \"{{ lookup('file', '/root/.ssh/id_rsa.pub') }}\" }} state=present\"";
//			JSONObject module = new JSONObject();
//			module.put("name", "raw");
//			module.put("args", command);
//			paramMap.put("module", module);
//			logger.info("paramMap : " + JSON.toJSONString(paramMap));
//			return requestWorker.invoke(paramMap, this::notify, null);
			return new BocloudResult<>(false, "暂未开发");
		} catch (Exception e) {
			logger.error("添加节点免登陆异常：" + e.getMessage());
			return new BocloudResult(false, "添加节点免登陆异常：" + e.getMessage());
		}
	}

	private WorkerCallBack workerCallBack;

	public void notify(Map<String, Object> data, BocloudResult result) {
		WorkerCallBack workerCallBack = this.getWorkerCallBack();
		String operMsg = "kubernetes.node";
		String message = "";
		String nodeOperate = workerCallBack.getOperate();
		if ("add-node".equalsIgnoreCase(nodeOperate)) {
			message = "添加节点";
		}
		if ("del-node".equalsIgnoreCase(nodeOperate)) {
			message = "删除节点";
		}
		logger.info("操作 ： " + nodeOperate + " result : " + result);
		if (result.isFailed()) {
			RequestContext context = new RequestContext();
			context.setTarget(workerCallBack.getUserId());
			resourceEventPublisher.send(new OperateResult(false, message + "失败：" + result.getMessage(), operMsg,
					MapTools.simpleMap(Common.VENDORID, workerCallBack.getCloudVendor().getId()),
					OperateResult.OperateCategory.ResourceEvent, context));
			return;
		}
		if (workerCallBack.login) {
			logger.info(nodeOperate + " start ============ ");
			workerCallBack.setLogin(Boolean.FALSE);
			handleNode(workerCallBack.getCloudVendor(), workerCallBack.getOperate(), workerCallBack.getNodeIp());
		} else {
			RequestContext context = new RequestContext();
			context.setTarget(workerCallBack.getUserId());
			syncService.sync(workerCallBack.getCloudVendor().getId(), context, false);
			resourceEventPublisher.send(new OperateResult(true, message + "成功: 正在进行数据同步...", operMsg,
					MapTools.simpleMap(Common.VENDORID, workerCallBack.getCloudVendor().getId()),
					OperateResult.OperateCategory.ResourceEvent, context));
		}
	}

	public Object buildTargets(CloudVendor cloudVendor) throws Exception {
		Encryptor encryptor = new AESEncrptor();
		String password = encryptor.decrypt(cloudVendor.getDeployPassword(), null);
		List<JSONObject> targetsObjects = new ArrayList<JSONObject>();
		JSONObject targetsObject = new JSONObject();
		targetsObject.put("host", cloudVendor.getDeployUrl());
		targetsObject.put("category", "Linux");
		targetsObject.put("port", 22);
		targetsObject.put("pasd", password);
		targetsObject.put("user", cloudVendor.getDeployUsername());
		targetsObjects.add(targetsObject);
		return targetsObjects;
	}

	class WorkerCallBack {

		private CloudVendor cloudVendor;
		private Long userId;
		private Boolean login;
		private String operate;
		private String nodeIp;

		public CloudVendor getCloudVendor() {
			return cloudVendor;
		}

		public void setCloudVendor(CloudVendor cloudVendor) {
			this.cloudVendor = cloudVendor;
		}

		public Long getUserId() {
			return userId;
		}

		public void setUserId(Long userId) {
			this.userId = userId;
		}

		public String getOperate() {
			return operate;
		}

		public void setOperate(String operate) {
			this.operate = operate;
		}

		public WorkerCallBack() {
			super();
		}

		public String getNodeIp() {
			return nodeIp;
		}

		public void setNodeIp(String nodeIp) {
			this.nodeIp = nodeIp;
		}

		public Boolean getLogin() {
			return login;
		}

		public void setLogin(Boolean login) {
			this.login = login;
		}

		public WorkerCallBack(CloudVendor cloudVendor, Long userId, Boolean login, String operate, String nodeIp) {
			super();
			this.cloudVendor = cloudVendor;
			this.userId = userId;
			this.login = login;
			this.operate = operate;
			this.nodeIp = nodeIp;
		}

	}

	public WorkerCallBack getWorkerCallBack() {
		return workerCallBack;
	}

	public void setWorkerCallBack(WorkerCallBack workerCallBack) {
		this.workerCallBack = workerCallBack;
	}

}
