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

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.network.SecurityGroupRuleDriver;
import com.bocloud.cmp.model.SecurityGroupRuleModel;
import com.bocloud.common.model.*;
import com.bocloud.common.utils.Common;
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.SecurityGroup;
import com.bocloud.ims.entity.resource.SecurityGroupRule;
import com.bocloud.ims.entity.resource.Vdc;
import com.bocloud.ims.interfaces.resource.fusionsphere.FusionSphereSecurityGroupRuleService;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.SecurityGroupRepository;
import com.bocloud.ims.repository.resource.SecurityGroupRuleRepository;
import com.bocloud.ims.repository.resource.VdcRepository;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 安全组规则Service接口实现
 *
 * @author weiwei
 */
@Slf4j
@Service
public class FusionSphereSecurityGroupRuleServiceImpl implements FusionSphereSecurityGroupRuleService {

    private static OperateResult.OperateCategory operateCategory = OperateResult.OperateCategory.ResourceEvent;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @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 VdcRepository vdcRepository;


    @Override
    public BocloudResult<GridBean<SecurityGroupRule>> list(Pager pager, RequestContext context) {
        List<Param> params = Optional.ofNullable(pager.getParams()).orElse(new ArrayList<>());
        Map<String, String> sorter = Optional.ofNullable(pager.getSorter()).orElse(Maps.newHashMap());
        Integer page = Optional.ofNullable(pager.getPage()).orElse(1);
        Integer rows = Optional.ofNullable(pager.getRows()).orElse(10);
        try {
            int total = securityGroupRuleRepository.count(params);
            List<SecurityGroupRule> list = securityGroupRuleRepository.list(page, rows, params, sorter);
            GridBean<SecurityGroupRule> gridBean = new GridBean<>(page, rows, total, list);
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            log.error("list PortGroup error!", e);
            return new BocloudResult<>(false, "查询失败:" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<List<SecurityGroupRule>> create(SecurityGroupRule rule, RequestContext context) {
        try {
            SecurityGroup group = securityGroupRepository.query(rule.getGroupId());
            Assert.notNull(group, "安全组不存在");
            CloudVendor vendor = cloudVendorRepository.query(rule.getVendorId());
            Assert.notNull(vendor, "平台不存在");
            Vdc vdc = vdcRepository.query(group.getVdcId());
            Assert.notNull(vdc, "站点不存在");

            SecurityGroupRuleModel model = new SecurityGroupRuleModel();
            BeanUtils.copyProperties(rule, model);
            model.setGroupUuid(group.getGroupUuid());
            model.setVdcUri(vdc.getUri());

            taskExecutor.execute(() -> {
                String operate = vendor.getType().toLowerCase() + ".grouprule";
                String message = "创建资源失败";
                BocloudResult result = securityGroupRuleDriver.create(vendor.getUuid(), null, model);
                try {
                    if (result.isSuccess()) {
                        message = "创建资源成功";
                        BocloudResult bocloudResult = securityGroupRuleDriver.list(vendor.getUuid(), null, model);
                        List<SecurityGroupRule> securityGroups = JSONObject.parseArray(JSONObject.toJSONString(bocloudResult.getData()), SecurityGroupRule.class);
                        securityGroupRuleRepository.removeBySgId(group.getId(), group.getMenderId());
                        for (SecurityGroupRule rule1 : securityGroups) {
                            if (rule1.getIpRanges().indexOf("-") > -1) {
                                rule1.setType("subnet");
                            } else if (rule1.getIpRanges().indexOf("/") > -1) {
                                rule1.setType("ip");
                            }
                            rule1.setGroupId(group.getId());
                            rule1.setTenantId(group.getTenantId());
                            rule1.setProjectId(group.getProjectId());
                            rule1.setVendorId(group.getVendorId());
                            rule1.setCreatorId(group.getCreatorId());
                            rule1.setGmtCreate(new Date());
                            securityGroupRuleRepository.save(rule1);
                        }
                    } else {
                        log.error("创建资源失败：" + result.getMessage());
                        message = result.getMessage();
                    }
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), message, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), operateCategory, context));
                } catch (Exception e) {
                    log.error("create resource fail:", e);
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), message, operate, MapTools.simpleMap(
                            "vendorId", vendor.getId()), operateCategory, context));
                }
            });
            return new BocloudResult<>(true, "任务已下发，正在执行...");
        } catch (Exception e) {
            log.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, "云平台不存在");
            Vdc vdc = vdcRepository.query(group.getVdcId());
            Assert.notNull(vdc, "站点不存在");

            SecurityGroupRuleModel ruleModel = new SecurityGroupRuleModel();
            BeanUtils.copyProperties(rule, ruleModel);
            ruleModel.setGroupUuid(group.getGroupUuid());
            ruleModel.setVdcUri(vdc.getUri());

            taskExecutor.execute(() -> {
                String operate = vendor.getType().toLowerCase() + ".grouprule";
                String message = "删除资源失败";
                BocloudResult result = securityGroupRuleDriver.remove(ruleModel, vendor.getUuid(), group.getRegionId());
                try {
                    if (result.isSuccess()) {
                        message = "删除资源成功";
                        securityGroupRuleRepository.remove(id, context.getTarget());
                    } else {
                        log.error("删除资源失败：" + result.getMessage());
                        message = result.getMessage();
                    }
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), message, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), operateCategory, context));
                } catch (Exception e) {
                    log.error("remove resource fail:", e);
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), message, operate,
                            MapTools.simpleMap("vendorId", vendor.getId()), operateCategory, context));
                }
            });
            return new BocloudResult<>(true, "任务已下发，正在执行...");
        } catch (Exception e) {
            log.error("remove resource error!", e);
            return new BocloudResult<>(false, "删除失败:" + e.getMessage());
        }
    }

    @Override
    public BocloudResult<SecurityGroupRule> detail(Long id, RequestContext context) {
        try {
            SecurityGroupRule rule = securityGroupRuleRepository.query(id);
            return new BocloudResult<>(true, rule, "查询成功！");
        } catch (Exception e) {
            log.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) {
            log.error("batch remove security group rule fail:", e);
            return new BocloudResult<>(false, "批量删除任务下发失败");
        }
        return new BocloudResult<>(true, "批量删除任务已下发，正在执行...");
    }

}
