package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.network.SecurityGroupRuleDriver;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.model.SecurityGroupRuleModel;
import com.bocloud.common.model.*;
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.*;
import com.bocloud.ims.interfaces.resource.SecurityGroupRuleService;
import com.bocloud.ims.interfaces.resource.VendorProjectService;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.OSTenantRepository;
import com.bocloud.ims.repository.resource.SecurityGroupRepository;
import com.bocloud.ims.repository.resource.SecurityGroupRuleRepository;
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;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 安全组规则Service接口实现
 *
 * @author weiwei
 */
@Service("securityGroupRuleService")
public class SecurityGroupRuleServiceImpl implements SecurityGroupRuleService {

	private static Logger logger = LoggerFactory.getLogger(SecurityGroupRuleServiceImpl.class);
	@Autowired
	private LockFactory lockFactory;
	@Autowired
	private SecurityGroupRuleRepository securityGroupRuleRepository;
	@Autowired
	private SecurityGroupRepository securityGroupRepository;
	@Autowired
	private CloudVendorRepository cloudVendorRepository;
	@Autowired
	private SecurityGroupRuleDriver securityGroupRuleDriver;
	@Autowired
	private ResourceEventPublisher resourceEventPublisher;
	@Autowired
	private VendorProjectService vendorProjectService;
	@Autowired
	private OSTenantRepository osTenantRepository;

	@Override
	public BocloudResult<GridBean<SecurityGroupRule>> list(Pager pager) {
		try {

			int page = pager.getPage();
			int rows = pager.getRows();
			List<Param> params = pager.getParams();
			Map<String, String> sorter = pager.getSorter();
			boolean simple = pager.getSimple();

			if (null == params) {
				params = new ArrayList<>();
			}
			if (null == sorter) {
				sorter = Maps.newHashMap();
			}
			sorter.put("gmtCreate", Common.ONE);
			int total = securityGroupRuleRepository.count(params);
			List<SecurityGroupRule> list = securityGroupRuleRepository.list(page, rows, params, sorter);
			GridBean gridBean = GridHelper.getBean(page, rows, total, list);
			return new BocloudResult<>(true, gridBean, "查询成功");
		} catch (Exception e) {
			logger.error("Query SecurityGroup list fail:", e);
			return new BocloudResult<>(false, "查询失败", null, null);
		}
	}

	@Override
	public BocloudResult<SecurityGroupRule> create(SecurityGroupRule rule) {
		try {
			SecurityGroup group = securityGroupRepository.query(rule.getGroupId());
			if (null == group) {
				logger.error("get security group failure!");
				return new BocloudResult<>(false, "安全组不存在");
			}
			CloudVendor vendor = cloudVendorRepository.query(group.getVendorId());
			if (null == vendor) {
				logger.error("get cloudVendor and reg failure!");
				return new BocloudResult<>(false, "平台不存在");
			}
			rule.setGroupUuid(group.getGroupUuid());
			rule.setGroupId(group.getId());
			rule.setTenantId(group.getTenantId());
			rule.setProjectId(group.getProjectId());
			if (CloudProvider.TENCENT.name().equals(vendor.getType())
					|| CloudProvider.TCE.name().equals(vendor.getType())) {
				List<Param> params = Lists.newArrayList();
				Map<String, Object> simpleMap = MapTools.simpleMap(Common.VENDORID, vendor.getId());
				simpleMap.put("protocol", rule.getProtocol());
				simpleMap.put("portMax", rule.getPortMax());
				simpleMap.put("portMin", rule.getPortMin());
				simpleMap.put("remoteIpPrefix", rule.getRemoteIpPrefix());
				simpleMap.put("direction", rule.getDirection());
				simpleMap.put("groupId", group.getId());
				params.add(new Param(simpleMap, Sign.EQ));
				int count = securityGroupRuleRepository.count(params);
				if (count > 0) {
					logger.error("get cloudVendor and reg failure!");
					return new BocloudResult<>(false, "当前协议端口已存在！");
				}
				if (null == rule.getAction()) {
					rule.setAction("ACCEPT");
				}
			}
			Assert.notNull(rule.getProtocol(), "协议不允许为空！");
			if ((CloudProvider.PQCLOUD.name().equals(vendor.getType())
					|| CloudProvider.QCLOUD.name().equals(vendor.getType()))
					&& "ICMP".equalsIgnoreCase(rule.getProtocol())) {
				rule.setPortMax(null);
				rule.setPortMin(null);
			}
			SecurityGroupRuleModel model = new SecurityGroupRuleModel();
			BeanUtils.copyProperties(rule, model);
			// TCE设置规则下标为自增方式
			if (CloudProvider.TCE.name().equals(vendor.getType())) {
				List<SecurityGroupRule> securityGroupRules = securityGroupRuleRepository.listBySgId(group.getId(),
						rule.getDirection());
				model.setSgrIndex(securityGroupRules.size());
				rule.setSgrIndex(securityGroupRules.size());
			}
			BocloudResult result = null;
			TenantProvider provider = vendorProjectService.getAncestorProject(vendor.getId(), group.getTenantId());
			if (null == provider) {
				OSTenant osTenant = osTenantRepository.getByTenantUuid(group.getTenantUuid(), vendor.getId());
				String projectName = null;
				if (null != osTenant) {
					projectName = osTenant.getName();
				}
				result = securityGroupRuleDriver.create(vendor.getUuid(), projectName, group.getRegionId(), model);
			} else {
				result = securityGroupRuleDriver.create(vendor.getUuid(), provider.getProjectName(),
						group.getRegionId(), model);
			}
			if (result.isFailed()) {
				return new BocloudResult<>(false, result.getMessage());
			}
			SecurityGroupRule groupRule = JSONObject.parseObject(JSONObject.toJSONString(result.getData()),
					SecurityGroupRule.class);
			rule.setRuleUuid(groupRule.getRuleUuid());
			rule.setVendorId(group.getVendorId());
			rule.setProtocol(groupRule.getProtocol());
			rule.setEtherType(groupRule.getEtherType());
			rule.setPortMin(groupRule.getPortMin());
			securityGroupRuleRepository.save(rule);
			return new BocloudResult<>(true, rule, "创建成功!");
		} catch (Exception e) {
			logger.error("create failure:", e);
			return new BocloudResult<>(false, "创建失败：" + e.getMessage());
		}
	}

	@Override
	public BocloudResult<String> remove(Long id, RequestContext context) {
		String path = SecurityGroup.class.getSimpleName() + "_" + id;
		try (BocloudACLock lock = lockFactory.getACLock(path)) {
			Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
			SecurityGroupRule rule = securityGroupRuleRepository.query(id);
			Assert.notNull(rule, "安全组规则不存在");
			SecurityGroup group = securityGroupRepository.query(rule.getGroupId());
			Assert.notNull(group, "安全组不存在");
			CloudVendor vendor = cloudVendorRepository.query(rule.getVendorId());
			Assert.notNull(vendor, "云平台不存在");
			BocloudResult bocloudResult = null;
			if (CloudProvider.TENCENT.name().equals(vendor.getType())
					|| CloudProvider.TCE.name().equals(vendor.getType())
					|| CloudProvider.AZURE.name().equals(vendor.getType())
					|| CloudProvider.AWS.name().equals(vendor.getType())
					|| CloudProvider.ALIYUN.name().equals(vendor.getType())
					|| CloudProvider.HUAWEI.name().equals(vendor.getType())
					|| CloudProvider.JDCLOUD.name().equals(vendor.getType())
			) {
				SecurityGroupRuleModel ruleModel = new SecurityGroupRuleModel();
				BeanUtils.copyProperties(rule, ruleModel);
				ruleModel.setGroupUuid(group.getGroupUuid());
				bocloudResult = securityGroupRuleDriver.remove(ruleModel, vendor.getUuid(), group.getRegionId());
			} else {
				OSTenant osTenant = osTenantRepository.getByTenantUuid(group.getTenantUuid(), vendor.getId());
				String projectName = null;
				if (null != osTenant) {
					projectName = osTenant.getName();
				}
				bocloudResult = securityGroupRuleDriver.remove(rule.getRuleUuid(), vendor.getUuid(), projectName,
						group.getRegionId());
			}
			if (null == bocloudResult || !bocloudResult.isSuccess()) {
				return new BocloudResult<>(false, "删除失败!");
			}
			securityGroupRuleRepository.remove(id, context.getTarget());
			return new BocloudResult<>(true, "删除成功");
		} catch (Exception e) {
			logger.error("remove failure:", e);
			return new BocloudResult<>(false, "删除失败:" + e.getMessage());
		}
	}

	@Override
	public BocloudResult<SecurityGroupRule> detail(Long id) {
		try {
			SecurityGroupRule rule = securityGroupRuleRepository.query(id);
			return new BocloudResult<>(true, rule, "查询成功！");
		} catch (Exception e) {
			logger.error("get security group tule detail failure:", e);
			return new BocloudResult<>(false, "查询失败!");
		}
	}

	@Override
	public BocloudResult<String> batchRemove(List<Long> idArray, RequestContext context) {
		if (ListTool.isEmpty(idArray)) {
			return new BocloudResult<>(false, "没有需要删除的安全组规则！");
		}
		try {
			List<BocloudResult> succList = Lists.newArrayList();
			List<BocloudResult> failList = Lists.newArrayList();
			Long vendorId = null;
			for (Long id : idArray) {
				SecurityGroupRule rule = securityGroupRuleRepository.query(id);
				if (null != rule) {
					if (null == vendorId) {
						vendorId = rule.getVendorId();
					}
					BocloudResult result = remove(id, context);
					if (result.isSuccess()) {
						succList.add(new BocloudResult<>(true, "【" + rule.getRuleUuid() + "】删除成功"));
					} else {
						failList.add(
								new BocloudResult<>(false, "【" + rule.getRuleUuid() + "】删除失败：" + result.getMessage()));
					}
				}
			}
			CloudVendor vendor = cloudVendorRepository.query(vendorId);
			String operate = vendor.getType().toLowerCase() + ".rule";
			// 删除成功的数量
			int success = succList.size();
			// 删除失败的数量
			int fail = failList.size();
			String content = null;
			if (fail == idArray.size()) {
				content = "安全组规则批量删除失败，详情如下：\n";
				for (BocloudResult bocloudResult : failList) {
					content += bocloudResult.getMessage() + "\n";
				}
				resourceEventPublisher.send(
						new OperateResult(false, content, operate, MapTools.simpleMap(Common.VENDORID, vendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
			} else {
				content = "安全组规则批量删除成功【" + success + "】个,失败【" + fail + "】个，详情如下：\n";
				for (BocloudResult bocloudResult : succList) {
					content += bocloudResult.getMessage() + "\n";
				}
				for (BocloudResult bocloudResult : failList) {
					content += bocloudResult.getMessage() + "\n";
				}
				resourceEventPublisher.send(
						new OperateResult(true, content, operate, MapTools.simpleMap(Common.VENDORID, vendor.getId()),
								OperateResult.OperateCategory.ResourceEvent, context));
			}
		} catch (Exception e) {
			logger.error("batch remove security group rule fail:", e);
			return new BocloudResult<>(false, "批量删除任务下发失败");
		}
		return new BocloudResult<>(true, "批量删除任务已下发，正在执行...");
	}

}
