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

import java.util.ArrayList;
import java.util.HashMap;
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.ServiceDriver;
import com.bocloud.cmp.model.NotifyMessage;
import com.bocloud.cmp.model.kubernetes.ServiceModel;
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.JSONTools;
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.KubeDaemonSet;
import com.bocloud.ims.entity.resource.kubernetes.KubeDeployment;
import com.bocloud.ims.entity.resource.kubernetes.KubeNamespace;
import com.bocloud.ims.entity.resource.kubernetes.KubePod;
import com.bocloud.ims.entity.resource.kubernetes.KubeService;
import com.bocloud.ims.interfaces.resource.ResourcePoolService;
import com.bocloud.ims.interfaces.resource.kubernetes.KubeServiceService;
import com.bocloud.ims.repository.kubernetes.KubeDaemonSetRepository;
import com.bocloud.ims.repository.kubernetes.KubeDeploymentRepository;
import com.bocloud.ims.repository.kubernetes.KubeNamespaceRepository;
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.repository.resource.PoolGroupRepository;
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("kubeServiceService")
public class KubeServiceServiceImpl implements KubeServiceService {

	private static final Logger logger = LoggerFactory.getLogger(KubeServiceServiceImpl.class);
	@Autowired
	private CloudVendorRepository cloudVendorRepository;
	@Autowired
	private KubeServiceRepository kubeServiceRepository;
	@Autowired
	private KubeNamespaceRepository namespaceRepository;
	@Autowired
	private LockFactory lockFactory;
	@Autowired
	private ServiceDriver serviceDriver;
	@Autowired
	private ResourceEventPublisher resourceEventPublisher;
	@Autowired
	private AmqpTemplate amqpTemplate;
	@Autowired
	private PoolGroupRepository poolGroupRepository;
	@Autowired
	private KubeDeploymentRepository kubeDeploymentRepository;
	@Autowired
	private KubeDaemonSetRepository kubeDaemonSetRepository;
	@Autowired
	private KubeNamespaceRepository kubeNamespaceRepository;
	@Autowired
	private ResourcePoolService resourcePoolService;
	@Autowired
	private KubePodRepository kubePodRepository;

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

	@Override
	public BocloudResult create(KubeService service, RequestContext context) {
		try {
			CloudVendor vendor = cloudVendorRepository.query(service.getVendorId());
			if (null == vendor) {
				return new BocloudResult(false, "获取云供应商失败");
			}
			String yamlText = service.getYamlText();
			if (StringUtils.isEmpty(yamlText)) {
				return createService(service, context);
			}
			ServiceModel model = new ServiceModel();
			BeanUtils.copyProperties(service, model);
			BocloudResult bocloudResult = serviceDriver.create(vendor.getUuid(), model);
			if (bocloudResult.isFailed()) {
				return new BocloudResult(false, bocloudResult.getMessage());
			}
			ServiceModel serviceModel = (ServiceModel) bocloudResult.getData();
			BeanUtils.copyProperties(serviceModel, service);
			service.setCreatorId(context.getTarget());
			service.setMenderId(context.getTarget());
			service.setVendorId(vendor.getId());
			if (StringUtils.isEmpty(model.getNamespace())) {
				KubeNamespace kubeNamespace = namespaceRepository.queryByName(model.getNamespace(), vendor.getId());
				if (null != kubeNamespace) {
					service.setNsId(kubeNamespace.getId());
				}
			}
			this.kubeServiceRepository.save(service);
			// 发送给云平台统计队列对云平台重新统计
			JSONObject jsonObject = new JSONObject();
			jsonObject.put(Common.VENDORID, vendor.getId());
			amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);
			return new BocloudResult(true, "添加成功");
		} catch (Exception e) {
			logger.error("create service error", e);
			return new BocloudResult(false, "添加失败");
		}
	}

	private BocloudResult createService(KubeService service, RequestContext context) {
		try {
			Long appId = service.getAppId();
			KubeNamespace kubeNamespace = kubeNamespaceRepository.query(appId);
			if (null == kubeNamespace) {
				return new BocloudResult(false, "应用异常！");
			}
			Long serviceId = service.getServiceId();
			String serviceKind = service.getKind();
			Map<String, String> labelsMap = new HashMap<String, String>();
			labelsMap.put("serviceName", service.getName());
			Long vendorId = null;
			String parentUuid = null;
			if ("Deployment".equalsIgnoreCase(serviceKind)) {
				KubeDeployment kubeDeployment = kubeDeploymentRepository.query(serviceId);
				if (null == kubeDeployment) {
					return new BocloudResult(false, "服务信息异常！");
				}
				parentUuid = kubeDeployment.getUid();
				vendorId = kubeDeployment.getVendorId();
				labelsMap.put("applicationName", kubeDeployment.getName());
			} else if ("DaemonSet".equalsIgnoreCase(serviceKind)) {
				KubeDaemonSet kubeDaemonSet = kubeDaemonSetRepository.query(serviceId);
				if (null == kubeDaemonSet) {
					return new BocloudResult(false, "服务信息异常！");
				}
				parentUuid = kubeDaemonSet.getUid();
				vendorId = kubeDaemonSet.getVendorId();
				labelsMap.put("applicationName", kubeDaemonSet.getName());
			} else {
				return new BocloudResult(false, "参数无效！");
			}
			CloudVendor cloudVendor = cloudVendorRepository.query(vendorId);
			ServiceModel model = new ServiceModel();
			BeanUtils.copyProperties(service, model);
			model.setLabelsMap(labelsMap);
			model.setNamespace(kubeNamespace.getName());
			Map<String, String> selectorMap = new HashMap<>();
			selectorMap.put("applicationName", labelsMap.get("applicationName"));
			model.setSelectorMap(selectorMap);
			BocloudResult bocloudResult = serviceDriver.create(cloudVendor.getUuid(), model);
			if (bocloudResult.isFailed()) {
				return bocloudResult;
			}
			ServiceModel serviceModel = (ServiceModel) bocloudResult.getData();
			BeanUtils.copyProperties(serviceModel, service);
			service.setCreatorId(context.getTarget());
			service.setTenantId(context.getTenant());
			service.setMenderId(context.getTarget());
			service.setVendorId(cloudVendor.getId());
			service.setNsId(kubeNamespace.getId());
			service.setNamespace(kubeNamespace.getName());
			service.setAppId(kubeNamespace.getId());
			service.setAppName(kubeNamespace.getName());
			this.kubeServiceRepository.save(service);
			if (!StringUtils.isEmpty(parentUuid)) {
				List<Param> podParams = new ArrayList<Param>();
				podParams.add(new Param(MapTools.simpleMap("vendor_id", cloudVendor.getId()), Sign.EQ));
				podParams.add(new Param(MapTools.simpleMap("ns_name", kubeNamespace.getName()), Sign.EQ));
				if ("Deployment".equalsIgnoreCase(serviceKind)) {
					podParams.add(new Param(MapTools.simpleMap("deployment_uid", parentUuid), Sign.EQ));
				} else if ("DaemonSet".equalsIgnoreCase(serviceKind)) {
					podParams.add(new Param(MapTools.simpleMap("parent_resource_uid", parentUuid), Sign.EQ));
				}
				List<KubePod> listByParams = kubePodRepository.listByParams(podParams);
				if (!ListTool.isEmpty(listByParams)) {
					for (KubePod kubePod : listByParams) {
						kubePod.setServiceId(service.getId());
						kubePod.setServiceName(service.getName());
					}
					kubePodRepository.batchUpdate(listByParams, listByParams.size());
				}
			}
			// 发送给云平台统计队列对云平台重新统计
			JSONObject jsonObject = new JSONObject();
			jsonObject.put(Common.VENDORID, cloudVendor.getId());
			amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);
			return new BocloudResult(true, "添加成功");

		} catch (Exception e) {
			logger.error("负载创建失败：" + e.getMessage());
			return new BocloudResult(false, "负载创建失败：" + e.getMessage());
		}
	}

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

	private BocloudResult modifyService(KubeService service, RequestContext context) {
		try {
			KubeService kubeService = kubeServiceRepository.query(service.getId());
			if (null == kubeService) {
				return new BocloudResult(false, "参数异常！");
			}
			CloudVendor cloudVendor = cloudVendorRepository.query(kubeService.getVendorId());
			ServiceModel model = new ServiceModel();
			model.setName(kubeService.getName());
			model.setNamespace(kubeService.getNamespace());
			model.setServiceConfig(service.getServiceConfig());
			model.setNamespace(kubeService.getNamespace());
			BocloudResult bocloudResult = serviceDriver.modify(cloudVendor.getUuid(), model);
			if (bocloudResult.isFailed()) {
				return new BocloudResult(false, bocloudResult.getMessage());
			}
			ServiceModel createModel = (ServiceModel) bocloudResult.getData();
			kubeService.setPorts(createModel.getPorts());
			kubeService.setYamlText(createModel.getYamlText());
			kubeService.setInternalEndpoint(createModel.getInternalEndpoint());
			kubeServiceRepository.update(kubeService);
			return new BocloudResult(true, "编辑成功");

		} catch (Exception e) {
			logger.error("编辑失败：" + e.getMessage());
			return new BocloudResult(false, "编辑失败：" + e.getMessage());
		}

	}

	@Override
	public BocloudResult remove(Long id, RequestContext context) {
		String path = KubeService.class.getSimpleName() + "_" + id;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			KubeService service = this.kubeServiceRepository.query(id);
			if (null == service) {
				return new BocloudResult(false, "数据不存在");
			}
			CloudVendor vendor = cloudVendorRepository.query(service.getVendorId());
			if (null == vendor) {
				return new BocloudResult(false, "获取云供应商失败");
			}
			ServiceModel model = new ServiceModel();
			BeanUtils.copyProperties(service, model);
			BocloudResult bocloudResult = serviceDriver.remove(model, vendor.getUuid());
			if (bocloudResult.isFailed()) {
				return new BocloudResult(false, bocloudResult.getMessage());
			}
			this.kubeServiceRepository.remove(id, context.getTarget());
			List<Param> params = new ArrayList<>();
			params.add(new Param(MapTools.simpleMap("vendor_id", vendor.getId()), Sign.EQ));
			params.add(new Param(MapTools.simpleMap("ns_id", service.getNsId()), Sign.EQ));
			params.add(new Param(MapTools.simpleMap("service_id", service.getId()), Sign.EQ));
			List<KubePod> listByParams = kubePodRepository.listByParams(params);
			if (!ListTool.isEmpty(listByParams)) {
				for (KubePod kubePod : listByParams) {
					kubePod.setServiceId(null);
					kubePod.setServiceName(null);
				}
				kubePodRepository.batchUpdate(listByParams, listByParams.size());
			}
			// 发送给云平台统计队列对云平台重新统计
			JSONObject jsonObject = new JSONObject();
			jsonObject.put(Common.VENDORID, vendor.getId());
			amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);
			return new BocloudResult(true, "删除成功");
		} catch (Exception e) {
			logger.error("Remove service error:", e);
			return new BocloudResult(false, "删除失败");
		}
	}

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

	@Override
	public BocloudResult apply(String params, RequestContext context) {
		try {
			JSONObject object = JSONTools.isJSONObj(params);
			if (null == object) {
				return new BocloudResult(false, "参数格式错误！");
			}
			Long vendorId = object.getLong(Common.VENDORID);
			CloudVendor cloudVendor = cloudVendorRepository.query(vendorId);
			if (null == cloudVendor) {
				return new BocloudResult(false, "云平台不存在！");
			}

			String yamlText = object.getString("yamlText");
			if (StringUtils.isEmpty(yamlText)) {
				return new BocloudResult(false, "参数格式错误！");
			}
			new Thread(new Runnable() {
				@Override
				public void run() {
					BocloudResult bocloudResult = new BocloudResult(false, "服务申请失败！");
					try {
						ServiceModel model = new ServiceModel();
						model.setYamlText(yamlText);
						bocloudResult = serviceDriver.create(cloudVendor.getUuid(), model);
						if (bocloudResult.isSuccess()) {
							ServiceModel serviceModel = (ServiceModel) bocloudResult.getData();
							KubeService service = new KubeService();
							BeanUtils.copyProperties(serviceModel, service);
							service.setCreatorId(context.getTarget());
							service.setMenderId(context.getTarget());
							service.setTenantId(context.getTenant());
							service.setVendorId(cloudVendor.getId());
							if (StringUtils.isEmpty(model.getNamespace())) {
								KubeNamespace kubeNamespace = namespaceRepository.queryByName(model.getNamespace(),
										cloudVendor.getId());
								if (null != kubeNamespace) {
									service.setNsId(kubeNamespace.getId());
								}
							}
							kubeServiceRepository.save(service);
							bocloudResult.setMessage("K8S服务申请成功！服务名称：【" + service.getName() + "】");
						}
					} catch (Exception e) {
						logger.error("服务申请失败：" + e.getMessage());
						bocloudResult.setMessage("服务申请失败：" + e.getMessage());
					}
					// 站内信
					NotifyMessage message = new NotifyMessage(context, "K8S服务申请", bocloudResult.getMessage(), true,
							true);
					amqpTemplate.convertAndSend("event.notice.queue", message);
					resourceEventPublisher.send(new OperateResult(bocloudResult.isSuccess(), bocloudResult.getMessage(),
							"kubernetes.service", MapTools.simpleMap(Common.VENDORID, cloudVendor.getId()),
							OperateResult.OperateCategory.ResourceEvent, context));
				}
			}).start();
			return new BocloudResult(true, "服务申请任务已下发...正在执行！");
		} catch (Exception e) {
			logger.error("Get service error：", e);
			return new BocloudResult(false, e.getMessage());
		}
	}

}
