package com.bocloud.ims.service.utils;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.model.Butler;
import com.bocloud.cmp.provider.ButlerRepository;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.interfaces.resource.CloudVendorService;
import com.bocloud.service.client.ServiceClient;
import org.apache.curator.framework.recipes.cache.NodeCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 云服务供应商注册器
 *
 * @author wangyu
 * @version 1.0
 * @since 2017年9月22日
 */
@Component
public class ProviderRegister implements InitializingBean {

	private static Logger logger = LoggerFactory.getLogger(ProviderRegister.class);
	private static NodeCache nodeCache;
	@Autowired
	private CloudVendorService providerService;
	private final ServiceClient serviceClient;

	public void updateProvider(List<CloudVendor> providers) throws Exception {
		Map<String, String> map = convertProviders(providers);
		String data = JSONObject.parseObject(JSONObject.toJSONString(map)).toString();
		serviceClient.putButler(data);
	}

	@Autowired
	public ProviderRegister(ServiceClient serviceClient) {
		this.serviceClient = serviceClient;
	}

	/**
	 * 服务启动时将数据库中的云服务供应商信息注册到ZooKeeper中
	 *
	 * @throws Exception
	 */
	public void start() throws Exception {
		serviceClient.putButler(null);
		List<CloudVendor> providers = providerService.listAll();
		Map<String, String> map = convertProviders(providers);
		String data = JSONObject.parseObject(JSONObject.toJSONString(map)).toString();
		serviceClient.putButler(data);
		ButlerRepository.getInstance().update(data);
		// 处理ZooKeeper上的云服务供应商数据发生变化时的处理逻辑：更新内部的缓存
		nodeCache.getListenable().addListener(() -> {
			logger.info("Cloud Service Provider data changed,Refresh them in cache!");
			ButlerRepository.getInstance().update(new String(nodeCache.getCurrentData().getData(), "utf-8"));
			logger.info("Refresh Cloud Service Provider Success!");
		});
	}

	private Map<String, String> convertProviders(List<CloudVendor> providers) {
		Map<String, String> map = new HashMap<>();
		Butler butler = null;
		for (CloudVendor provider : providers) {
			JSONObject authentication = JSONObject.parseObject(provider.getAuthentication());
			String regions = authentication.getString("regions") == null ? "" : authentication.getString("regions");
			butler = new Butler(provider.getName(), provider.getUuid(), authentication.getString("account"),
					authentication.getString("password"), authentication.getString("accessKey"),
					authentication.getString("secretKey"), regions, authentication.getString("tenant"),
					authentication.getString("address"), provider.getType(), authentication.getString("domainName"),
					authentication.getString("projectName"), provider.getVersion(), null,
					authentication.getString("regionId"));
			if (CloudProvider.KUBERNETES.name().equalsIgnoreCase(provider.getType())) {
				butler.setToken(authentication.getString("token"));
			} else if (CloudProvider.FUSIONCLOUD.name().equalsIgnoreCase(provider.getType())
					|| CloudProvider.MANAGEONE.name().equalsIgnoreCase(provider.getType())
					|| CloudProvider.TIANYI.name().equalsIgnoreCase(provider.getType())) {
				butler.setProjectId(authentication.getString("projectId"));
			} else if (CloudProvider.AZURE.name().equalsIgnoreCase(provider.getType())) {
				butler.setSubscriptionId(authentication.getString("subscriptionId"));
				butler.setClientId(authentication.getString("clientId"));
				butler.setVersion(authentication.getString("version"));
			} else if (CloudProvider.AWS.name().equalsIgnoreCase(provider.getType())) {
				butler.setRegionId("cn-north-1");
			}
			map.put(provider.getUuid(), butler.toString());
		}
		return map;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		nodeCache = new NodeCache(this.serviceClient.getClient().getClient(), serviceClient.getService().getButler(),
				false);
		nodeCache.start(true);
		this.start();
	}

}
