package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.compute.ServerDriver;
import com.bocloud.cmp.driver.network.TagDriver;
import com.bocloud.cmp.driver.storage.VolumeDriver;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.model.ServerModel;
import com.bocloud.cmp.model.TagModel;
import com.bocloud.cmp.model.VmTagParam;
import com.bocloud.cmp.model.VolumeModel;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.Pager;
import com.bocloud.common.model.Param;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.Tag;
import com.bocloud.ims.interfaces.resource.TagService;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.TagRepository;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.beanutils.BeanUtils;
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 java.util.*;
import java.util.concurrent.TimeUnit;

@Service("tagService")
public class TagServiceImpl implements TagService {
	private static Logger logger = LoggerFactory.getLogger(TagServiceImpl.class);
	@Autowired
	private TagRepository tagRepository;
	@Autowired
	private CloudVendorRepository cloudVendorRepository;
	@Autowired
	private TagDriver tagDriver;
	@Autowired
	private ServerDriver serverDriver;
	@Autowired
	private VolumeDriver volumeDriver;
	@Autowired
	private LockFactory lockFactory;

	@Override
	public BocloudResult<GridBean<Tag>> list(Pager pager) {
		try {
			int page = pager.getPage();
			int rows = pager.getRows();
			List<Param> params = pager.getParams();
			Map<String, String> sorter = pager.getSorter();

			params = Optional.ofNullable(params).orElse(new ArrayList<>());
			sorter = Optional.ofNullable(sorter).orElse(Maps.newHashMap());
			sorter.put("gmtCreate", Common.ONE);
			int total = tagRepository.count(params);
			List<Tag> list = tagRepository.list(page, rows, params, sorter);
			GridBean gridBean = GridHelper.getBean(page, rows, total, list);
			return new BocloudResult<>(true, gridBean, "查询成功");
		} catch (Exception e) {
			logger.error("list tag failure:", e);
			return new BocloudResult<>(false, "查询失败", null, null);
		}
	}

	@Override
	public BocloudResult create(VmTagParam vmTagParam) {
		try {
			CloudVendor vendor = cloudVendorRepository.query(vmTagParam.getVendorId());
			Assert.notNull(vmTagParam, "参数格式错误");
			String regionId = vmTagParam.getRegionId();
			String resourceId = vmTagParam.getResourceId();
			String resourceType = vmTagParam.getResourceType();
			BocloudResult result = new BocloudResult<>(true, "");
			List<TagModel> tags = vmTagParam.getTags();
			Boolean isExist = false;
			Map<String, TagModel> hasMap = new HashMap<>();
			for (TagModel tag : tags) {
				if (hasMap.containsKey(tag.getKey())) {
					isExist = true;
					break;
				}
				hasMap.put(tag.getKey(), tag);
			}
			if (isExist) {
				return new BocloudResult<>(false, "创建失败,存在重复标签");
			}
			CloudProvider provider = CloudProvider.valueOf(vendor.getType());
			switch (provider) {
			case VMWARE:
				result = serverDriver.setFields(resourceId, vendor.getUuid(), null, tags);
				if (result.isSuccess()) {
					tagRepository.removeByRid(resourceId);
					List<Tag> tagList = new ArrayList<>();
					for (TagModel tag : tags) {
						Tag entiryTag = new Tag();
						BeanUtils.copyProperties(entiryTag, tag);
					}
					tagRepository.batchSave(tagList, 1000);
				}
				break;
			case ALIYUN:
				List<Tag> aliTagList = tagRepository.listByRid(resourceId);
				List<TagModel> aliOldTagModels = new ArrayList<>();
				for (Tag tag : aliTagList) {
					TagModel model = new TagModel();
					BeanUtils.copyProperties(model, tag);
					aliOldTagModels.add(model);
				}

				List<TagModel> aliTagModels = tags;
				for (TagModel tagModel : aliTagModels) {
					if (aliOldTagModels.contains(tagModel)) {
						aliOldTagModels.remove(tagModel);
					}
				}
				if ("disk".equalsIgnoreCase(resourceType)) {
					VolumeModel volumeModel = new VolumeModel();
					volumeModel.setVolumeUuid(resourceId);
					if (!ListTool.isEmpty(aliTagModels)) {
						volumeModel.setTagModels(aliTagModels);
						result = volumeDriver.createTag(vendor.getUuid(), regionId, volumeModel);
					}
					if (!ListTool.isEmpty(aliOldTagModels)) {
						volumeModel.setTagModels(aliOldTagModels);
						result = volumeDriver.removeTag(vendor.getUuid(), regionId, volumeModel);
					}
				}
				if ("instance".equalsIgnoreCase(resourceType)) {
					ServerModel serverModel = new ServerModel();
					serverModel.setInstanceId(resourceId);
					if (!ListTool.isEmpty(aliTagModels)) {
						serverModel.setTagModels(aliTagModels);
						result = serverDriver.createTag(vendor.getUuid(), regionId, serverModel);
					}
					if (!ListTool.isEmpty(aliOldTagModels)) {
						serverModel.setTagModels(aliOldTagModels);
						result = serverDriver.removeTag(vendor.getUuid(), regionId, serverModel);
					}
				}
				if (result.isSuccess()) {
					tagRepository.removeByRid(resourceId);
					List<Tag> tagList = new ArrayList<>();
					for (TagModel tag : tags) {
						Tag entiryTag = new Tag();
						BeanUtils.copyProperties(entiryTag, tag);
						entiryTag.setVendorId(vmTagParam.getVendorId());
						entiryTag.setRegionId(regionId);
						tagList.add(entiryTag);
					}
					if (!ListTool.isEmpty(tagList)) {
						tagRepository.batchSave(tagList, 1000);
					}
				}
				break;
			case HUAWEI:
			case HCSO:
				List<Tag> tagList = tagRepository.listByRid(resourceId);

				List<TagModel> oldTagModels = new ArrayList<>();
				for (Tag tag : tagList) {
					TagModel model = new TagModel();
					BeanUtils.copyProperties(model, tag);
					oldTagModels.add(model);
				}
				List<TagModel> tagModels = tags;
				for (TagModel tagModel : tagModels) {
					if (oldTagModels.contains(tagModel)) {
						oldTagModels.remove(tagModel);
					}
				}
				if ("volume".equalsIgnoreCase(resourceType)) {
					VolumeModel volumeModel = new VolumeModel();
					volumeModel.setVolumeUuid(resourceId);
					if (!ListTool.isEmpty(tagModels)) {
						volumeModel.setTagModels(tagModels);
						result = volumeDriver.createTag(vendor.getUuid(), regionId, volumeModel);
					}
					if (!ListTool.isEmpty(oldTagModels)) {
						volumeModel.setTagModels(oldTagModels);
						result = volumeDriver.removeTag(vendor.getUuid(), regionId, volumeModel);
					}
				}
				if ("instance".equalsIgnoreCase(resourceType)) {
					ServerModel serverModel = new ServerModel();
					serverModel.setInstanceId(tags.get(0).getResourceId());
					if (!ListTool.isEmpty(tagModels)) {
						serverModel.setTagModels(tagModels);
						result = serverDriver.createTag(vendor.getUuid(), regionId, serverModel);
					}
					if (!ListTool.isEmpty(oldTagModels)) {
						serverModel.setTagModels(oldTagModels);
						result = serverDriver.removeTag(vendor.getUuid(), regionId, serverModel);
					}
				}
				if (result.isSuccess()) {
					tagRepository.removeByRid(resourceId);
					List<Tag> huaweiTagList = new ArrayList<>();
					for (TagModel tag : tags) {
						Tag entiryTag = new Tag();
						BeanUtils.copyProperties(entiryTag, tag);
						entiryTag.setVendorId(vmTagParam.getVendorId());
						entiryTag.setRegionId(regionId);
						tagList.add(entiryTag);
					}
					if (!ListTool.isEmpty(tagList)) {
						tagRepository.batchSave(huaweiTagList, 1000);
					}
				}
				break;
			case AWS:
				oldTagModels = getTagModels(tagRepository.listByRid(tags.get(0).getResourceId()));
				for (TagModel tagModel :
						tags) {
					if (oldTagModels.contains(tagModel)) {
						oldTagModels.remove(tagModel);
					}
				}

				if (!ListTool.isEmpty(oldTagModels)) {
					result = tagDriver.remove(vendor.getUuid(), oldTagModels, regionId);
					if (result.isFailed()) {
						return new BocloudResult(false, "创建失败:" + result.getMessage(), null, null);
					}
				}
				if (!ListTool.isEmpty(tags)) {
					result = tagDriver.create(vendor.getUuid(), tags, regionId);
				}
				if (result.isFailed()) {
					return new BocloudResult(false, "创建失败:" + result.getMessage(), null, null);
				}
				tagRepository.removeByRid(tags.get(0).getResourceId());
				List<Tag> newTags = JSONObject.parseArray(JSONObject.toJSONString(result.getData()), Tag.class);
				for (Tag tag : newTags) {
					tag.setVendorId(vmTagParam.getVendorId());
					tag.setRegionId(regionId);
				}
				tagRepository.batchSave(newTags, 1000);
				break;
			default:
				break;
			}
			return new BocloudResult<>(true, "操作成功");
		} catch (Exception e) {
			logger.error("create tag failure:", e);
			return new BocloudResult<>(false, "操作失败： " + e.getMessage());
		}
	}

	private List<TagModel> getTagModels(List<Tag> tags) {
		List<TagModel> tagModels = new ArrayList<>();
		for (Tag tag : tags) {
			tagModels.add(new TagModel(tag.getKey(), tag.getValue(), tag.getResourceId()));
		}
		return tagModels;
	}

	@Override
	public BocloudResult remove(Long id) {
		String path = Tag.class.getSimpleName() + "_" + id;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			Tag tag = tagRepository.query(id);
			if (null == tag) {
				logger.warn("Tag does not exist!");
				return new BocloudResult<>(false, "数据不存在");
			}
			CloudVendor vendor = cloudVendorRepository.query(tag.getVendorId());
			if (null == vendor) {
				return new BocloudResult<>(false, "平台不存在");
			}
			BocloudResult result = null;
			CloudProvider provider = CloudProvider.valueOf(vendor.getType());
			switch (provider) {
			case VMWARE:
				List<String> keys = Lists.newArrayList();
				keys.add(tag.getKey());
				result = serverDriver.removeFields(tag.getResourceId(), vendor.getUuid(), null, keys);
				if (result.isSuccess()) {
					this.tagRepository.remove(id);
				}
				break;
			default:
				break;
			}
			return new BocloudResult<>(true, "删除成功");
		} catch (Exception e) {
			logger.error("Remove tag error:", e);
			return new BocloudResult<>(false, "删除失败");
		}
	}
}
