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.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.kubernetes.DaemonSetDriver;
import com.bocloud.cmp.driver.kubernetes.PodDriver;
import com.bocloud.cmp.model.kubernetes.ContainerModel;
import com.bocloud.cmp.model.kubernetes.DaemonSetModel;
import com.bocloud.cmp.model.kubernetes.PodModel;
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.Sign;
import com.bocloud.common.model.SimpleBean;
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.KubeContainer;
import com.bocloud.ims.entity.resource.kubernetes.KubeDaemonSet;
import com.bocloud.ims.entity.resource.kubernetes.KubeDeployment;
import com.bocloud.ims.entity.resource.kubernetes.KubeNamespace;
import com.bocloud.ims.entity.resource.kubernetes.KubeNode;
import com.bocloud.ims.entity.resource.kubernetes.KubePod;
import com.bocloud.ims.entity.resource.kubernetes.KubeService;
import com.bocloud.ims.interfaces.resource.kubernetes.KubeDaemonsetService;
import com.bocloud.ims.repository.kubernetes.KubeContainerRepository;
import com.bocloud.ims.repository.kubernetes.KubeDaemonSetRepository;
import com.bocloud.ims.repository.kubernetes.KubeNamespaceRepository;
import com.bocloud.ims.repository.kubernetes.KubeNodeRepository;
import com.bocloud.ims.repository.kubernetes.KubePodRepository;
import com.bocloud.ims.repository.kubernetes.KubeServiceRepository;
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.Lists;
import com.google.common.collect.Maps;

@Service("kubeDaemonsetService")
public class KubeDaemonsetServiceImpl implements KubeDaemonsetService {

	private static final Logger logger = LoggerFactory.getLogger(KubeDaemonsetServiceImpl.class);
	@Autowired
	private CloudVendorRepository cloudVendorRepository;
	@Autowired
	private DaemonSetDriver daemonSetDriver;
	@Autowired
	private ResourceEventPublisher resourceEventPublisher;
	@Autowired
	private KubeDaemonSetRepository kubeDaemonSetRepository;
	@Autowired
	private LockFactory lockFactory;
	@Autowired
	private KubeNamespaceRepository kubeNamespaceRepository;
	@Autowired
	private KubeNodeRepository kubeNodeRepository;
	@Autowired
	private KubeServiceRepository kubeServiceRepository;
	@Autowired
	private KubePodRepository kubePodRepository;
	@Autowired
	private AmqpTemplate amqpTemplate;
	@Autowired
	private KubeContainerRepository kubeContainerRepository;
	@Autowired
	private PodDriver podDriver;

	@Override
	public BocloudResult list(Pager pager, RequestContext context) {
		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 = 0;
			List<KubeDaemonSet> list = null;
			total = this.kubeDaemonSetRepository.count(params);
			if (simple) {
				List<SimpleBean> beans = this.kubeDaemonSetRepository.list(params, sorter);
				gridBean = new GridBean(1, 1, total, beans);
			} else {
				list = this.kubeDaemonSetRepository.list(page, rows, params, sorter);
				gridBean = GridHelper.getBean(page, rows, total, list);
			}
			return new BocloudResult(true, gridBean, "查询成功");
		} catch (Exception e) {
			logger.error("Query KubeDeployment list fail:", e);
			return new BocloudResult(false, "查询失败");
		}
	}

	@Override
	public BocloudResult create(KubeDaemonSet kubeDaemonSet, RequestContext context) {
		try {
			CloudVendor vendor = cloudVendorRepository.query(kubeDaemonSet.getVendorId());
			if (null == vendor) {
				return new BocloudResult(false, "获取云供应商失败");
			}
			String yamlText = kubeDaemonSet.getYamlText();
			if (StringUtils.isEmpty(yamlText)) {
				return new BocloudResult(false, "参数格式错误！");
			}
			new Thread(new Runnable() {
				@Override
				public void run() {
					BocloudResult bocloudResult = new BocloudResult(false, "创建失败！");
					try {
						DaemonSetModel model = new DaemonSetModel();
						BeanUtils.copyProperties(kubeDaemonSet, model);
						bocloudResult = daemonSetDriver.create(vendor.getUuid(), model);
						if (bocloudResult.isSuccess()) {
							DaemonSetModel daemonSetModel = (DaemonSetModel) bocloudResult.getData();
							BeanUtils.copyProperties(daemonSetModel, kubeDaemonSet);
							kubeDaemonSet.setCreatorId(context.getTarget());
							kubeDaemonSet.setMenderId(context.getTarget());
							kubeDaemonSet.setVendorId(vendor.getId());
							if (StringUtils.isEmpty(daemonSetModel.getNamespace())) {
								KubeNamespace kubeNamespace = kubeNamespaceRepository
										.queryByName(daemonSetModel.getNamespace(), vendor.getId());
								if (null != kubeNamespace) {
									kubeDaemonSet.setNsId(kubeNamespace.getId());
								}
							}
							kubeDaemonSetRepository.save(kubeDaemonSet);
							List<PodModel> podModels = daemonSetModel.getPodModels();
							if (null != podModels && !podModels.isEmpty()) {
								KubePod pod = null;
								for (PodModel createModel : podModels) {
									pod = new KubePod();
									BeanUtils.copyProperties(createModel, pod);
									pod.setCreatorId(context.getTarget());
									pod.setMenderId(context.getTarget());
									pod.setVendorId(vendor.getId());
									if (StringUtils.isEmpty(createModel.getNamespace())) {
										KubeNamespace kubeNamespace = kubeNamespaceRepository
												.queryByName(createModel.getNamespace(), vendor.getId());
										if (null != kubeNamespace) {
											pod.setNsId(kubeNamespace.getId());
										}
									}
									if (StringUtils.isEmpty(createModel.getNodeName())) {
										KubeNode node = kubeNodeRepository.querByName(createModel.getNodeName(),
												vendor.getId());
										if (null != node) {
											pod.setNodeId(node.getId());
										}
									}
									if (StringUtils.isEmpty(createModel.getServiceName())) {
										KubeService service = kubeServiceRepository
												.querByName(createModel.getServiceName(), vendor.getId());
										if (null != service) {
											pod.setServiceId(service.getId());
										}
									}
									kubePodRepository.save(pod);
									syncContainers(createModel.getKubeContainers(), pod, vendor, context);
								}
							}
							// 发送给云平台统计队列对云平台重新统计
							JSONObject jsonObject = new JSONObject();
							jsonObject.put(Common.VENDORID, vendor.getId());
							amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);
						}
					} catch (Exception e) {
						bocloudResult.setMessage(e.getMessage());
					}
					resourceEventPublisher.send(new OperateResult(bocloudResult.isSuccess(), bocloudResult.getMessage(),
							"kubernetes.service", MapTools.simpleMap(Common.VENDORID, vendor.getId()),
							OperateResult.OperateCategory.ResourceEvent, context));
				}
			}).start();
			return new BocloudResult(true, "任务已下发，正在执行...");
		} catch (Exception e) {
			logger.error("create daemonset error", e);
			return new BocloudResult(false, "添加失败");
		}
	}

	private void syncContainers(List<ContainerModel> kubeContainerModels, KubePod pod, CloudVendor vendor,
			RequestContext context) throws Exception {
		if (ListTool.isEmpty(kubeContainerModels)) {
			kubeContainerRepository.remove(vendor.getId(), pod.getId(), context.getTarget());
			return;
		}
		List<KubeContainer> kubeContainers = kubeContainerRepository.listByVendor(vendor.getId(), pod.getId());
		Map<String, KubeContainer> kubeContainerMap = Maps.newHashMap();
		for (KubeContainer kubeContainer : kubeContainers) {
			String key = kubeContainer.getContainerId();
			if (kubeContainerMap.containsKey(key)) {
				kubeContainerRepository.remove(vendor.getId(), pod.getId(), context.getTarget());
			} else {
				kubeContainerMap.put(key, kubeContainer);
			}
		}
		for (ContainerModel containerModel : kubeContainerModels) {
			KubeContainer kubeContainer = new KubeContainer();
			String key = containerModel.getContainerId();
			if (kubeContainerMap.containsKey(key)) {
				kubeContainer = kubeContainerMap.get(key);
				BeanUtils.copyProperties(containerModel, kubeContainer);
				kubeContainer.setMenderId(context.getTarget());
				kubeContainer.setCreatorId(context.getTarget());
				kubeContainer.setVendorId(pod.getVendorId());
				kubeContainer.setNsId(pod.getNsId());
				kubeContainer.setNamespace(pod.getNamespace());
				kubeContainer.setNodeId(pod.getNodeId());
				kubeContainer.setNodeName(pod.getNodeName());
				kubeContainer.setServiceId(pod.getServiceId());
				kubeContainer.setServiceName(pod.getServiceName());
				kubeContainer.setPodId(pod.getId());
				kubeContainer.setPodName(pod.getName());
				kubeContainerRepository.update(kubeContainer);
				kubeContainerMap.remove(key);
				continue;
			}
			BeanUtils.copyProperties(containerModel, kubeContainer);
			kubeContainer.setMenderId(context.getTarget());
			kubeContainer.setCreatorId(context.getTarget());
			kubeContainer.setVendorId(pod.getVendorId());
			kubeContainer.setNsId(pod.getNsId());
			kubeContainer.setNamespace(pod.getNamespace());
			kubeContainer.setNodeId(pod.getNodeId());
			kubeContainer.setNodeName(pod.getNodeName());
			kubeContainer.setServiceId(pod.getServiceId());
			kubeContainer.setServiceName(pod.getServiceName());
			kubeContainer.setPodId(pod.getId());
			kubeContainer.setPodName(pod.getName());
			kubeContainerRepository.save(kubeContainer);
		}
		for (KubeContainer kubeContainer : kubeContainerMap.values()) {
			kubeContainerRepository.remove(kubeContainer.getId(), context.getTarget());
		}

	}

	@Override
	public BocloudResult modify(KubeDaemonSet kubeDaemonSet, RequestContext context) {
		String path = KubeDeployment.class.getSimpleName() + "_" + kubeDaemonSet.getId();
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			KubeDaemonSet daemonSet = kubeDaemonSetRepository.query(kubeDaemonSet.getId());
			if (null == daemonSet) {
				logger.warn("daemonSet does not exist!");
				return new BocloudResult(false, "数据不存在");
			}
			CloudVendor vendor = cloudVendorRepository.query(daemonSet.getVendorId());
			if (null == vendor) {
				return new BocloudResult(false, "获取云供应商失败");
			}
			String yamlText = kubeDaemonSet.getYamlText();
			if (StringUtils.isEmpty(yamlText)) {
				return new BocloudResult(false, "参数格式错误！");
			}
			JSONObject parseObject = JSONObject.parseObject(yamlText, JSONObject.class);
			JSONObject jsonObject = parseObject.getJSONObject("metadata");
			String newName = jsonObject.getString("name");
			String namespace = jsonObject.getString("namespace");
			if (!daemonSet.getName().equals(newName) || !daemonSet.getNamespace().equals(namespace)) {
				return new BocloudResult(false, "服务命名空间/名称不允许修改！");
			}
			DaemonSetModel model = new DaemonSetModel();
			BeanUtils.copyProperties(kubeDaemonSet, model);
			BocloudResult bocloudResult = daemonSetDriver.modify(vendor.getUuid(), model);
			if (bocloudResult.isFailed()) {
				return new BocloudResult(false, bocloudResult.getMessage());
			}
			DaemonSetModel createModel = (DaemonSetModel) bocloudResult.getData();
			BeanUtils.copyProperties(createModel, daemonSet);
			kubeDaemonSetRepository.update(daemonSet);
			return new BocloudResult(true, "修改成功");
		} catch (Exception e) {
			logger.error("Modify daemonSet fail:", e);
			return new BocloudResult(false, "修改失败:" + e.getMessage());
		}
	}

	@Override
	public BocloudResult remove(Long id, RequestContext context) {
		String path = KubeDeployment.class.getSimpleName() + "_" + id;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			KubeDaemonSet kubeDaemonSet = kubeDaemonSetRepository.query(id);
			if (null == kubeDaemonSet) {
				return new BocloudResult(false, "数据不存在");
			}
			CloudVendor vendor = cloudVendorRepository.query(kubeDaemonSet.getVendorId());
			if (null == vendor) {
				return new BocloudResult(false, "获取云供应商失败");
			}
			new Thread(new Runnable() {
				@Override
				public void run() {
					String operate = "kubernetes.service";
					try {
						DaemonSetModel model = new DaemonSetModel();
						BeanUtils.copyProperties(kubeDaemonSet, model);
						BocloudResult bocloudResult = daemonSetDriver.remove(model, vendor.getUuid());
						if (bocloudResult.isSuccess()) {
							kubeDaemonSetRepository.remove(id, context.getTarget());
							// 删除部署成功后 删除对应pod
							List<Param> params = new ArrayList<Param>();
							params.add(new Param(MapTools.simpleMap("parent_resource_uid", kubeDaemonSet.getUid()),
									Sign.EQ));
							params.add(
									new Param(MapTools.simpleMap("vendor_id", kubeDaemonSet.getVendorId()), Sign.EQ));
							List<KubePod> kubePods = kubePodRepository.listByParams(params);
							if (null != kubePods && !kubePods.isEmpty()) {
								for (KubePod kubePod : kubePods) {
									PodModel podModel = new PodModel();
									BeanUtils.copyProperties(kubePod, podModel);
									podDriver.remove(podModel, vendor.getUuid());
									kubePodRepository.remove(kubePod.getId(), context.getTarget());
									kubeContainerRepository.remove(vendor.getId(), kubePod.getId(),
											context.getTarget());
								}
							}
							// 发送给云平台统计队列对云平台重新统计
							JSONObject jsonObject = new JSONObject();
							jsonObject.put(Common.VENDORID, vendor.getId());
							amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);
						}
						resourceEventPublisher
								.send(new OperateResult(bocloudResult.isSuccess(), bocloudResult.getMessage(), operate,
										MapTools.simpleMap(Common.VENDORID, vendor.getId()),
										OperateResult.OperateCategory.ResourceEvent, context));

					} catch (Exception e) {
						logger.error("删除DaemonSet失败：" + e.getMessage());
						resourceEventPublisher.send(new OperateResult(false, "删除DaemonSet失败：" + e.getMessage(), operate,
								MapTools.simpleMap(Common.VENDORID, vendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
					}
				}
			}).start();
			return new BocloudResult(true, "任务已下发，正在执行...");
		} catch (Exception e) {
			logger.error("Remove deployment error:", e);
			return new BocloudResult(false, "删除失败");
		}
	}

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

	@Override
	public BocloudResult apply(String params, RequestContext context) {
		return new BocloudResult(true, "开发中...");
	}

}
