package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.network.FloatIPDriver;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.entity.enums.ResourceCategory;
import com.bocloud.cmp.model.FloatingIpModel;
import com.bocloud.cmp.model.PortFixedIpModel;
import com.bocloud.cmp.model.PortModel;
import com.bocloud.cmp.model.common.*;
import com.bocloud.cmp.model.common.OrderMessage.Operation;
import com.bocloud.common.enums.ResourceCatalog;
import com.bocloud.common.exception.BoCloudDBException;
import com.bocloud.common.model.*;
import com.bocloud.common.model.RequestContext.Catalog;
import com.bocloud.common.utils.*;
import com.bocloud.ims.entity.common.Business;
import com.bocloud.ims.entity.common.Project;
import com.bocloud.ims.entity.common.Tenant;
import com.bocloud.ims.entity.common.User;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.interfaces.manageone.ManageOneAccountService;
import com.bocloud.ims.interfaces.resource.ElasticIpService;
import com.bocloud.ims.interfaces.resource.FloatingIpService;
import com.bocloud.ims.interfaces.resource.LabelService;
import com.bocloud.ims.interfaces.resource.VendorProjectService;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.service.internal.SmsBusinessService;
import com.bocloud.ims.service.internal.SmsProjectService;
import com.bocloud.ims.service.internal.SmsTenantService;
import com.bocloud.ims.service.internal.SmsUserService;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.nms.enums.OrderItemStatus;
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.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.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 浮动IP Service实现类
 *
 * @author weiwei
 */
@Service("floatingIpService")
public class FloatingIpServiceImpl implements FloatingIpService {

    private static Logger logger = LoggerFactory.getLogger(FloatingIpServiceImpl.class);
    @Autowired
    private FloatingIpRepository floatingIpRepository;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private PortRepository portRepository;
    @Autowired
    private SubnetRepository subnetRepository;
    @Autowired
    private RouterRepository routerRepository;
    @Autowired
    private PortFixedIpRepository portFixedIpRepository;
    @Autowired
    private NetworkRepository networkRepository;
    @Autowired
    private ObjectRelationRepository objectRelationRepository;
    @Autowired
    private SmsProjectService smsProjectService;
    @Autowired
    private FloatIPDriver floatIPDriver;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private NetworkCardRepository networkCardRepository;
    @Autowired
    private IpRepository ipRepository;
    @Autowired
    private SmsUserService smsUserService;
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private OSTenantRepository osTenantRepository;
    @Autowired
    private VendorProjectService vendorProjectService;
    @Autowired
    private ResourceEventRepository resourceEventRepository;
    @Autowired
    private ManageOneAccountService accountService;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private ElasticIpService elasticIpService;
    @Autowired
    private SmsBusinessService smsBusinessService;
    @Autowired
    private SmsTenantService smsTenantService;
    @Autowired
    private LabelService labelService;

    @Override
    public BocloudResult<GridBean<FloatingIp>> list(Pager pager, RequestContext context) {
        try {
            int page = pager.getPage();
            int rows = pager.getRows();
            List<Param> params = pager.getParams();
            Map<String, String> sorter = pager.getSorter();
            boolean simple = pager.getSimple();
            List<FloatingIp> list = Lists.newArrayList();
            GridBean gridBean = null;
            int total = 0;
            if (null == sorter) {
                sorter = Maps.newHashMap();
            }
            sorter.put("gmtCreate", Common.ONE);
            String vendorType = null;
            String labelContent = null;
            for (Param param : params) {
                Map<String, Object> paramMap = param.getParam();
                if (paramMap.containsKey("vendorType")) {
                    vendorType = String.valueOf(paramMap.get("vendorType"));
                    paramMap.remove("vendorType");
                }
                if (paramMap.containsKey("labelContent")) {
                    labelContent = paramMap.get("labelContent").toString();
                    paramMap.remove("labelContent");
                }
            }
            if (context.getCatalog().equals(Catalog.Tenant)) {
                // 租户能看到 1.属于当前租户的资源 2.租户下所有项目的资源
                List<Project> tenantProjects = smsProjectService.listTenantProjects(context.getTenant());
                List<Long> projectIds = tenantProjects.stream().map(Project::getId).collect(Collectors.toList());
                total = floatingIpRepository.count(null, context.getTenant(), projectIds, params, vendorType, labelContent);
                list = floatingIpRepository.list(page, rows, null, context.getTenant(), projectIds, params, sorter,
                        vendorType, labelContent);
                list = convertor(list);
                gridBean = new GridBean<>(page, rows, total, list);
            } else if (context.getCatalog().equals(Catalog.User)) {
                // 用户能看到 1.自己申请的资源 2.自己所在的资源可见项目（资源对项目下所有成员可见）下创建的资源 3.自己管理的项目下的资源
                List<Project> userManagerProjects = smsProjectService.listUserManagerProjects(context.getTarget());
                List<Project> visibleProjects = smsProjectService.listUserVisibleProjects(context.getTarget());
                List<Long> projectIds = new ArrayList<>();
                List<Long> userManagerProjectsIds =
                        userManagerProjects.stream().map(Project::getId).collect(Collectors.toList());
                if (!userManagerProjectsIds.isEmpty()) {
                    projectIds.addAll(userManagerProjectsIds);
                }
                List<Long> visibleProjectsIds =
                        visibleProjects.stream().map(Project::getId).collect(Collectors.toList());
                if (!visibleProjectsIds.isEmpty()) {
                    projectIds.addAll(visibleProjectsIds);
                }
                total = floatingIpRepository.count(context.getTarget(), null, projectIds, params, vendorType, labelContent);
                list = floatingIpRepository.list(page, rows, context.getTarget(), null, projectIds, params, sorter,
                        vendorType, labelContent);
                list = convertor(list);
                gridBean = new GridBean<>(page, rows, total, list);
            } else {
                total = floatingIpRepository.count(params, labelContent);
                if (simple) {
                    if (0 == context.getTenant()) {
                        params.add(new Param(MapTools.simpleMap(Common.TENANTID, 0), Sign.EQ));
                    }
                    List<SimpleBean> beans = floatingIpRepository.list(params, sorter, labelContent);
                    gridBean = new GridBean(1, 1, total, beans);
                } else {
                    list = floatingIpRepository.list(page, rows, params, sorter, labelContent);
                    gridBean = GridHelper.getBean(page, rows, total, list);
                }
            }
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("list floating ip fail:", e);
            return new BocloudResult<>(false, "查询失败", null, null);
        }
    }

    private List<FloatingIp> convertor(List<FloatingIp> list) {

        try {
            if (!ListTool.isEmpty(list)) {
                List<Long> tenantIds = new ArrayList<>();
                List<Long> userIds = new ArrayList<>();
                List<Long> businessIds = new ArrayList<>();
                List<Long> projectIds = new ArrayList<>();
                for (FloatingIp floatingIp : list) {
                    if (floatingIp.getTenantId() != null) {
                        tenantIds.add(floatingIp.getTenantId());
                    }
                    if (floatingIp.getBusinessId() != null) {
                        businessIds.add(floatingIp.getBusinessId());
                    }
                    if (floatingIp.getProjectId() != null) {
                        projectIds.add(floatingIp.getProjectId());
                    }
                    if (floatingIp.getCreatorId() != null) {
                        userIds.add(floatingIp.getCreatorId());
                    }
                    if (floatingIp.getOwnerId() != null) {
                        userIds.add(floatingIp.getOwnerId());
                    }
                    if (floatingIp.getMenderId() != null) {
                        userIds.add(floatingIp.getMenderId());
                    }
                }
                Map<Long, String> userMap = smsUserService.listUsersByIds(userIds).stream()
                        .collect(Collectors.toMap(User::getId, User::getName));
                Map<Long, String> projectMap = smsProjectService.listProjectsByIds(projectIds).stream()
                        .collect(Collectors.toMap(Project::getId, Project::getName));
                Map<Long, String> businessMap = smsBusinessService.listBusinesssByIds(businessIds).stream()
                        .collect(Collectors.toMap(Business::getId, Business::getName));
                Map<Long, String> tenantMap = smsTenantService.listTenantsByIds(tenantIds).stream()
                        .collect(Collectors.toMap(Tenant::getId, Tenant::getName));
                for (FloatingIp floatingIp : list) {
                    // 设置云主机归属信息
                    if (floatingIp.getTenantId() != null) {
                        floatingIp.setTenantName(tenantMap.get(floatingIp.getTenantId()));
                    }
                    if (floatingIp.getBusinessId() != null) {
                        floatingIp.setBusinessName(businessMap.get(floatingIp.getBusinessId()));
                    }
                    if (floatingIp.getProjectId() != null) {
                        floatingIp.setProjectName(projectMap.get(floatingIp.getProjectId()));
                    }
                    if (floatingIp.getCreatorId() != null) {
                        floatingIp.setCreatorName(userMap.get(floatingIp.getCreatorId()));
                    }
                    if (floatingIp.getOwnerId() != null) {
                        floatingIp.setOwnerName(userMap.get(floatingIp.getOwnerId()));
                    }
                    if (floatingIp.getMenderId() != null) {
                        floatingIp.setMenderName(userMap.get(floatingIp.getMenderId()));
                    }
                }
            }
        } catch (Exception e) {
            logger.error("获取浮动IP基本信息异常：" + e.getMessage());
        }
        return list;

    }

    @Override
    public BocloudResult condition(String condition) {
        try {
            JSONObject object = JSONObject.parseObject(condition);
            if ("count".equalsIgnoreCase(object.getString("condition"))) {
                return count(object.getLong("userId"), object.getLong("projectId"), object.getLong("tenantId"));
            }

            return new BocloudResult<>(false, "查询失败");
        } catch (Exception e) {
            logger.error("list floating ip fail:", e);
            return new BocloudResult<>(false, "查询失败", null, null);
        }
    }

    @Override
    public BocloudResult<FloatingIp> create(FloatingIp fIp, RequestContext context) {
        try {
            CloudVendor vendor = cloudVendorRepository.query(fIp.getVendorId());
            if (null == vendor) {
                logger.error("get cloudVendor failure!");
                return new BocloudResult<>(false, "平台不存在");
            }
            Long tenant = context.getTenant();
            FloatingIpModel model = new FloatingIpModel();
            Network network = new Network();
            if (CloudProvider.TENCENT.name().equals(vendor.getType())
                    || CloudProvider.QCLOUD.name().equals(vendor.getType())
                    || CloudProvider.TIANYI.name().equals(vendor.getType())) {
                // 腾讯云支持 批量申请 所以异步申请
                if (Catalog.Tenant.equals(context.getCatalog()) || Catalog.User.equals(context.getCatalog())) {
                    return applyFloatingIp(fIp, vendor, context);
                } else {
                    createFloatingIp(fIp, vendor, context);
                }
                return new BocloudResult<>(true, "IP申请任务已下发，正在执行...");
            } else if (CloudProvider.MANAGEONE.name().equals(vendor.getType())) {
            } else {
                if (null != tenant && 0 != tenant) {
                    List<Network> listExternalByVid = networkRepository.listExternalByVid(vendor.getId(), null);
                    if (!ListTool.isEmpty(listExternalByVid)) {
                        network = listExternalByVid.get(0);
                    }
                } else {
                    network = networkRepository.query(fIp.getNetworkId());
                }
                if (null == network) {
                    logger.error("get network failure!");
                    return new BocloudResult<>(false, "网络不存在");
                }
                List<Subnet> subnets = subnetRepository.listByNetworkUuid(network.getNetworkUuid(), vendor.getId());
                if (ListTool.isEmpty(subnets)) {
                    logger.error("network 【" + network.getName() + "】 no have subnet!");
                    return new BocloudResult<>(false, "网络下不存在子网");
                }
                fIp.setNetworkId(network.getId());
                model.setFloatingNetworkUuid(network.getNetworkUuid());
            }
            BocloudResult result = new BocloudResult(false, "操作失败");

            OSTenant osTenant = osTenantRepository.getByTenantId(context.getTenant(), vendor.getId());
            if (null == osTenant) {
                result = floatIPDriver.create(vendor.getUuid(), fIp.getOsTenantName(), model, fIp.getRegionId());
            } else {
                result = floatIPDriver.create(vendor.getUuid(), osTenant.getName(), model, fIp.getRegionId());
            }
            if (result.isFailed()) {
                return new BocloudResult<>(false, "浮动IP分配失败：" + result.getMessage());
            }
            model = JSONObject.parseObject(JSONObject.toJSONString(result.getData()), FloatingIpModel.class);
            model.setResourceLabel(fIp.getResourceLabel());
            BeanUtils.copyProperties(model, fIp);
            if (null == fIp.getTenantId() || 0 == fIp.getTenantId()) {
                fIp.setTenantId(context.getTenant());
            }
            if (null == fIp.getProjectId() || 0 == fIp.getProjectId()) {
                fIp.setProjectId(context.getProject());
            }
            if (null != fIp.getNetworkId()) {
                Network net = networkRepository.getByNetId(fIp.getFloatingNetworkUuid(), fIp.getVendorId());
                if (null != net) {
                    fIp.setNetworkId(net.getId());
                }
            }
            floatingIpRepository.save(fIp);
            List<PortModel> portModels = model.getPorts();
            if (!ListTool.isEmpty(portModels)) {
                for (PortModel portModel : portModels) {
                    Port port = new Port();
                    port.setCreatorId(context.getTarget());
                    port.setMenderId(context.getTarget());
                    port.setVendorId(vendor.getId());
                    port.setGmtCreate(new Date());
                    port.setGmtModify(new Date());
                    port.setNetworkId(network.getId());
                    BeanUtils.copyProperties(portModel, port);
                    portRepository.save(port);
                    List<PortFixedIpModel> fixedIpModels = portModel.getPortFixedIps();
                    if (!ListTool.isEmpty(fixedIpModels)) {
                        for (PortFixedIpModel fixedIpModel : fixedIpModels) {
                            PortFixedIp fixedIp = new PortFixedIp();
                            BeanUtils.copyProperties(fixedIpModel, fixedIp);
                            fixedIp.setPortId(port.getId());
                            fixedIp.setPortUuid(port.getPortUuid());
                            Subnet subnet = subnetRepository.getBySubId(fixedIpModel.getSubnetUuid());
                            if (null != subnet) {
                                fixedIp.setSubnetId(subnet.getId());
                            }
                            portFixedIpRepository.save(fixedIp);
                        }
                    }
                }
            }
            return new BocloudResult<>(true, fIp, "浮动IP分配成功");
        } catch (Exception e) {
            logger.error("create router failure:", e);
            return new BocloudResult<>(false, "创建失败!");
        }
    }

    private BocloudResult applyFloatingIp(FloatingIp fip, CloudVendor vendor, RequestContext context) {
        FloatingIpModel ipModel = new FloatingIpModel();
        Integer count = fip.getCount();
        if (null == count) {
            count = 1;
        }
        ipModel.setAddressCount(count);
        ipModel.setResourceGroupUuid(fip.getResourceGroupUuid());
        try {
            String content = "IP申请失败";
            BocloudResult result = floatIPDriver.create(vendor.getUuid(), ipModel, fip.getRegionId());
            FloatingIp floating = null;
            if (result.isSuccess()) {
                List<FloatingIpModel> parseArray = JSONObject.parseArray(JSONObject.toJSONString(result.getData()),
                        FloatingIpModel.class);
                if (null != parseArray && parseArray.size() > 0) {
                    FloatingIpModel floatingIpModel = parseArray.get(0);
                    floating = new FloatingIp();
                    BeanUtils.copyProperties(floatingIpModel, floating);
                    floating.setMenderId(fip.getMenderId() == null ? context.getTarget() : fip.getMenderId());
                    floating.setInstanceId(null);
                    floating.setRegionId(fip.getRegionId());
                    floating.setGmtModify(new Date());
                    floating.setTenantId(context.getTenant());
                    floating.setUuid(fip.getUuid());
                    floating.setProjectId(fip.getProjectId() == null ? context.getProject() : fip.getProjectId());
                    floating.setCreatorId(fip.getCreatorId() == null ? context.getTarget() : fip.getCreatorId());
                    floating.setVendorId(vendor.getId());
                    floating.setResourceLabel(fip.getResourceLabel());
                    floatingIpRepository.save(floating);
                    content = "浮动IP申请成功";
                }
            } else {
                content = result.getMessage();
            }
            return new BocloudResult<>(true, floating, content);
        } catch (Exception e) {
            logger.error("浮动IP申请失败：" + e.getMessage());
            return new BocloudResult<>(false, "浮动IP申请失败：" + e.getMessage());
        }
    }

    private void createFloatingIp(FloatingIp fIp, CloudVendor vendor, RequestContext context) {
        FloatingIpModel ipModel = new FloatingIpModel();
        Integer count = fIp.getCount();
        if (null == count) {
            count = 1;
        }
        ipModel.setAddressCount(count);
        ipModel.setResourceGroupUuid(fIp.getResourceGroupUuid());
        Integer fipCount = count;
        taskExecutor.execute(() -> {
            String path = CloudVendor.class.getSimpleName() + "_" + vendor.getId();
            String operate = vendor.getType().toLowerCase() + ".floating";
            try (BocloudACLock lock = lockFactory.getACLock(path)) {
                Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "当前平台可能存在同步任务：请求超时");
                for (int i = 0; i < fipCount; i++) {
                    String content = "IP申请失败";
                    BocloudResult result = floatIPDriver.create(vendor.getUuid(), ipModel, fIp.getRegionId());
                    if (result.isSuccess()) {
                        List<FloatingIpModel> parseArray = JSONObject
                                .parseArray(JSONObject.toJSONString(result.getData()), FloatingIpModel.class);
                        List<FloatingIp> saveList = null;
                        FloatingIp floating = null;
                        if (null != parseArray && parseArray.size() > 0) {
                            saveList = Lists.newArrayList();
                            for (FloatingIpModel floatingIpModel : parseArray) {
                                floating = new FloatingIp();
                                BeanUtils.copyProperties(floatingIpModel, floating);
                                floating.setMenderId(context.getTarget());
                                floating.setInstanceId(null);
                                floating.setRegionId(fIp.getRegionId());
                                floating.setGmtModify(new Date());
                                floating.setTenantId(0L);
                                floating.setProjectId(0L);
                                floating.setCreatorId(context.getTarget());
                                floating.setVendorId(vendor.getId());
                                floating.setResourceLabel(fIp.getResourceLabel());
                                saveList.add(floating);
                            }
                            try {
                                floatingIpRepository.batchSave(saveList, null);
                            } catch (Exception e) {
                                logger.error("save fail : " + e);
                                content = e.getMessage();
                            }
                            content = "浮动IP申请成功";
                        }
                    } else {
                        content = result.getMessage();
                    }
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), content, operate,
                            MapTools.simpleMap(Common.VENDORID, vendor.getId()),
                            OperateResult.OperateCategory.ResourceEvent, context));
                }
            } catch (Exception e) {
                logger.error("浮动IP申请失败：" + e.getMessage());
                resourceEventPublisher.send(new OperateResult(false, "浮动IP申请失败：" + e.getMessage(), operate,
                        MapTools.simpleMap(Common.VENDORID, vendor.getId()),
                        OperateResult.OperateCategory.ResourceEvent, context));
            }
        });
    }

    @Override
    public BocloudResult remove(Long id, RequestContext context) {
        String path = FloatingIp.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            FloatingIp fip = floatingIpRepository.query(id);
            if (null == fip) {
                return new BocloudResult<>(false, "浮动IP不存在");
            }
            CloudVendor vendor = cloudVendorRepository.query(fip.getVendorId());
            BocloudResult result = floatIPDriver.remove(fip.getFloatingIpUuid(), vendor.getUuid(), fip.getRegionId());
            if (result.isFailed()) {
                return new BocloudResult<>(false, "浮动IP【" + fip.getFloatingIpAddress() + "】释放失败:" + result.getMessage());
            }
            floatingIpRepository.remove(id, context.getTarget());
            List<Port> ports = portRepository.listByDeviceId(fip.getFloatingIpUuid(), fip.getVendorId());
            for (Port port : ports) {
                List<PortFixedIp> fixedIps = portFixedIpRepository.listByPortId(port.getId());
                for (PortFixedIp fixedIp : fixedIps) {
                    ipRepository.delete(fixedIp.getIpAddress(), fixedIp.getSubnetId(), port.getVendorId());
                }
                portFixedIpRepository.deleteByPortId(port.getId());
                portRepository.remove(port.getId(), context.getTarget());
            }
            // 租户端资源需要更新配额
            ObjectRelation objectRelation = objectRelationRepository.get(id, ResourceCategory.FloatingIp.name());
            if (null != objectRelation && fip.getTenantId() > 0L) {
                objectRelationRepository.deleteByRid(id, ResourceCategory.FloatingIp.name());
            }
            return new BocloudResult<>(true, "浮动IP【" + fip.getFloatingIpAddress() + "】释放成功");
        } catch (Exception e) {
            logger.error("remove floating ip fail:", e);
            return new BocloudResult<>(false, "释放失败");
        }
    }

    @Override
    public BocloudResult<FloatingIp> detail(Long id) {
        try {
            FloatingIp fip = floatingIpRepository.query(id);
            if (null == fip) {
                return new BocloudResult<>(false, "浮动IP不存在");
            }
            // 设置云主机归属
            if (null != fip.getOwnerId() && 0L != fip.getOwnerId()) {
                BocloudResult<User> ownerDetail = smsUserService.detail(fip.getOwnerId());
                User owner = ownerDetail.getData();
                if (owner != null) {
                    fip.setOwnerName(owner.getName());
                }
            }
            if (null != fip.getMenderId() && 0L != fip.getMenderId()) {
                BocloudResult<User> menderDetail = smsUserService.detail(fip.getMenderId());
                User mender = menderDetail.getData();
                if (mender != null) {
                    fip.setMenderName(mender.getName());
                }
            }
            if (null != fip.getCreatorId() && 0L != fip.getCreatorId()) {
                BocloudResult<User> creatorDetail = smsUserService.detail(fip.getCreatorId());
                User creator = creatorDetail.getData();
                if (creator != null) {
                    fip.setCreatorName(creator.getName());
                }
            }
            if (null != fip.getProjectId() && 0L != fip.getProjectId()) {
                BocloudResult<Project> projectResult = smsProjectService.detail(fip.getProjectId());
                if (projectResult.isFailed() || null == projectResult.getData()) {
                    return new BocloudResult(false, projectResult.getMessage());
                }
                Project project = projectResult.getData();
                if (null != project) {
                    fip.setProjectName(project.getName());
                }
            }
            if (null != fip.getBusinessId() && 0L != fip.getBusinessId()) {
                BocloudResult<Business> businessDetail = smsBusinessService.detail(fip.getBusinessId());
                Business business = businessDetail.getData();
                if (business != null) {
                    fip.setBusinessName(business.getName());
                }
            }
            if (null != fip.getTenantId() && 0L != fip.getTenantId()) {
                BocloudResult<Tenant> tenantDetail = smsTenantService.detail(fip.getTenantId());
                Tenant tenant = tenantDetail.getData();
                if (tenant != null) {
                    fip.setTenantName(tenant.getName());
                }
            }
            if (!StringUtils.isEmpty(fip.getTenantUuid())) {
                OSTenant osTenant = osTenantRepository.getByTenantUuid(fip.getTenantUuid(), fip.getVendorId());
                if (null != osTenant) {
                    fip.setOsTenantName(osTenant.getName());
                }
            }
            // 浮动ip标签
            List<JSONObject> parseArray = JSON.parseArray(fip.getResourceLabel(), JSONObject.class);
            if (!ListTool.isEmpty(parseArray)) {
                BocloudResult existsValues = labelService.isExistsValues(parseArray);
                if (existsValues.isFailed()) {
                    return existsValues;
                }
                fip.setResourceLabel(JSONObject.toJSONString(existsValues.getData()));
                floatingIpRepository.update(fip);
            }
            return new BocloudResult<>(true, fip, "查询成功!");
        } catch (Exception e) {
            logger.error("query router detail failure:", e);
            return new BocloudResult<>(false, "查询详情失败!");
        }
    }

    @Override
    public BocloudResult associate(Long id, Long portId, Long userId) {
        String path = FloatingIp.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            FloatingIp fip = floatingIpRepository.query(id);
            if (null == fip) {
                return new BocloudResult<>(false, "浮动IP不存在");
            }
            if (null != fip.getPortId()) {
                return new BocloudResult<>(false, "该浮动IP已关联端口");
            }
            Port port = portRepository.query(portId);
            if (null == port) {
                return new BocloudResult<>(false, "端口不存在");
            }
            FloatingIp floatingIp = floatingIpRepository.getByPortId(portId);
            if (null != floatingIp) {
                return new BocloudResult<>(false, "该端口已被其他浮动IP关联");
            }
            List<PortFixedIp> fixedIps = portFixedIpRepository.listByPortId(portId);
            if (ListTool.isEmpty(fixedIps)) {
                return new BocloudResult<>(false, "端口IP不存在");
            }
            Subnet subnet = subnetRepository.query(fixedIps.get(0).getSubnetId());
            if (null == subnet) {
                return new BocloudResult<>(false, "端口所在子网不存在");
            }
            /*
             * List<RouterSubnet> routerSubnets =
             * routerSubnetRepository.listBySubnet(subnet.getId()); if
             * (ListTool.isEmpty(routerSubnets)) { return new BocloudResult<>(false,
             * "绑定浮动IP的端口网络不可达"); } // 浮动IP关联的网络 Long networkId = fip.getNetworkId();
             * boolean flag = false; // 判断端口所在的子网下连接的路由是否有关联到浮动IP网络关联的路由上 for (RouterSubnet
             * routerSubnet : routerSubnets) { Router router =
             * routerRepository.query(routerSubnet.getRouterId()); if (null != router) { if
             * (router.getNetworkId() == networkId) { flag = true; break; } } } if (!flag) {
             * return new BocloudResult<>(false, "端口所在子网连接的路由连接外部网络和浮动IP所在的网络不一致"); }
             */
            CloudVendor vendor = cloudVendorRepository.query(fip.getVendorId());
            // 云供应商
            if (null == vendor) {
                logger.error("get cloudVendor failure!");
                return new BocloudResult<>(false, "云平台不存在!");
            }
            BocloudResult result =
                    floatIPDriver.associate(fip.getFloatingIpUuid(), port.getPortUuid(), vendor.getUuid());
            if (result.isFailed()) {
                return new BocloudResult<>(false,
                        "浮动IP【" + fip.getFloatingIpAddress() + "】关联失败:" + result.getMessage());
            }
            FloatingIpModel model =
                    JSONObject.parseObject(JSONObject.toJSONString(result.getData()), FloatingIpModel.class);
            fip.setStatus(model.getStatus());
            fip.setFixedIpAddress(model.getFixedIpAddress());
            fip.setPortUuid(port.getPortUuid());
            fip.setPortId(portId);
            fip.setRouterUuid(model.getRouterUuid());
            Router router = routerRepository.query(model.getRouterUuid(), fip.getVendorId());
            if (null != router) {
                fip.setRouterId(router.getId());
            }
            floatingIpRepository.update(fip);
            if (null != port.getDeviceUuid()) {
                CloudServer server = cloudServerRepository.getByInstanceId(port.getDeviceUuid(), vendor.getId());
                if (null != server) {
                    Resource resource = resourceRepository.query(ResourceCategory.Computer.name(),
                            ResourceCatalog.LOGICAL.name(), server.getId());
                    if (null != resource) {
                        List<String> ips = JSONObject.parseArray(resource.getPrivateIps(), String.class);
                        if (ListTool.isEmpty(ips)) {
                            ips = Lists.newArrayList();
                        }
                        ips.add(fip.getFloatingIpAddress());
                        resource.setPrivateIps(JSONObject.toJSONString(ips));
                        resourceRepository.update(resource);
                    }
                }
            }
            return new BocloudResult<>(true, "浮动IP【" + fip.getFloatingIpAddress() + "】关联成功");
        } catch (Exception e) {
            logger.error("Associate floating ip fail:", e);
            return new BocloudResult<>(false, "浮动IP关联失败");
        }
    }

    @Override
    public BocloudResult disassociate(Long id, RequestContext context) {
        String path = FloatingIp.class.getSimpleName() + "_" + id;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            FloatingIp fip = floatingIpRepository.query(id);
            if (null == fip) {
                return new BocloudResult<>(false, "浮动IP不存在");
            }
            CloudVendor vendor = cloudVendorRepository.query(fip.getVendorId());
            BocloudResult result = null;
            if (CloudProvider.TENCENT.name().equals(vendor.getType())
                    || CloudProvider.ALIYUN.name().equals(vendor.getType())
                    || CloudProvider.HUAWEI.name().equals(vendor.getType())
                    || CloudProvider.HCSO.name().equals(vendor.getType())
                    || CloudProvider.TIANYI.name().equals(vendor.getType())
                    || CloudProvider.QCLOUD.name().equals(vendor.getType())) {
                return publicDisassociate(fip, vendor, context);
            } else {
                if (null == fip.getPortId()) {
                    return new BocloudResult<>(false, "该浮动IP已解绑端口");
                }
                result = floatIPDriver.disassociate(fip.getFloatingIpUuid(), vendor.getUuid());
                if (result.isFailed()) {
                    return new BocloudResult<>(false, "浮动IP【" + fip.getFloatingIpAddress() + "】解绑失败");
                }
                Long portId = fip.getPortId();
                FloatingIpModel model =
                        JSONObject.parseObject(JSONObject.toJSONString(result.getData()), FloatingIpModel.class);
                fip.setFixedIpAddress(null);
                fip.setPortUuid(null);
                fip.setPortId(null);
                fip.setRouterUuid(null);
                fip.setRouterId(null);
                fip.setStatus(model.getStatus());
                floatingIpRepository.update(fip);
                Port port = portRepository.query(portId);
                if (null != port && null != port.getDeviceUuid()) {
                    CloudServer server = cloudServerRepository.getByInstanceId(port.getDeviceUuid(), vendor.getId());
                    if (null != server) {
                        Resource resource = resourceRepository.query(ResourceCategory.Computer.name(),
                                ResourceCatalog.LOGICAL.name(), server.getId());
                        if (null != resource) {
                            List<String> ips = JSONObject.parseArray(resource.getPrivateIps(), String.class);
                            if (!ListTool.isEmpty(ips)) {
                                ips.remove(fip.getFloatingIpAddress());
                            }
                            resource.setPrivateIps(JSONObject.toJSONString(ips));
                            resourceRepository.update(resource);
                        }
                    }
                }
            }
            return new BocloudResult<>(true, "浮动IP【" + fip.getFloatingIpAddress() + "】解绑成功");
        } catch (Exception e) {
            logger.error("Disassociate floating ip fail:", e);
            return new BocloudResult<>(false, "浮动IP解绑失败");
        }
    }

    private BocloudResult publicDisassociate(FloatingIp fip, CloudVendor vendor, RequestContext context) {
        taskExecutor.submit(new Runnable() {
            @Override
            public void run() {
                String operate = vendor.getType().toLowerCase() + ".floatingip";
                try {
                    FloatingIpModel floatingIpModel = new FloatingIpModel();
                    floatingIpModel.setFloatingIpUuid(fip.getFloatingIpUuid());
                    floatingIpModel.setInstanceId(fip.getInstanceId());
                    floatingIpModel.setFloatingIpAddress(fip.getFloatingIpAddress());
                    BocloudResult result =
                            floatIPDriver.disassociate(vendor.getUuid(), floatingIpModel, fip.getRegionId());
                    if (result.isFailed()) {
                        resourceEventPublisher
                                .send(new OperateResult(result.isSuccess(), "IP解绑失败：" + result.getMessage(), operate,
                                        MapTools.simpleMap(Common.VENDORID, vendor.getId()),
                                        OperateResult.OperateCategory.ResourceEvent, context));
                        return;
                    }
                    String instanceId = fip.getInstanceId();
                    String networkCardUuid = fip.getNetworkCardUuid();
                    FloatingIpModel model =
                            JSONObject.parseObject(JSONObject.toJSONString(result.getData()), FloatingIpModel.class);
                    fip.setInstanceId(null);
                    fip.setNetworkCardUuid(model.getNetworkCardUuid());
                    fip.setMenderId(context.getTarget());
                    fip.setGmtModify(new Date());
                    fip.setStatus(model.getStatus());
                    fip.setFixedIpAddress(null);
                    floatingIpRepository.update(fip);
                    CloudServer server = cloudServerRepository.getByInstanceId(instanceId);
                    if (null != server) {
                        List<String> publicIps = JSON.parseArray(server.getPublicIps(), String.class);
                        if (!ListTool.isEmpty(publicIps)) {
                            publicIps.remove(fip.getFloatingIpAddress());
                        }
                        server.setPublicIps(JSON.toJSONString(publicIps));
                        cloudServerRepository.update(server);
                        // 更新资源表
                        Resource resource = resourceRepository.query(ResourceCategory.Computer.name(),
                                ResourceCatalog.LOGICAL.name(), server.getId());
                        if (null != resource) {
                            List<String> ips = JSONObject.parseArray(resource.getPrivateIps(), String.class);
                            if (!ListTool.isEmpty(ips)) {
                                ips.remove(fip.getFloatingIpAddress());
                            }
                            resource.setPrivateIps(JSONObject.toJSONString(ips));
                            resourceRepository.update(resource);
                        }
                    }
                    if (CloudProvider.TIANYI.name().equals(vendor.getType())) {
                        NetworkCard networkCard =
                                networkCardRepository.getByNetworkCardUuid(networkCardUuid, vendor.getId());
                        if (null != networkCard) {
                            networkCard.setUsed(false);
                            networkCard.setFloatingIpUuid(null);
                            networkCardRepository.update(networkCard);
                        }
                    }
                    resourceEventPublisher.send(new OperateResult(true, "浮动IP解绑成功！", operate,
                            MapTools.simpleMap(Common.VENDORID, vendor.getId()),
                            OperateResult.OperateCategory.ResourceEvent, context));
                } catch (BoCloudDBException e) {
                    logger.error("浮动IP解绑失败：" + e.getMessage());
                    resourceEventPublisher.send(new OperateResult(false, "IP解绑失败：" + e.getMessage(), operate,
                            MapTools.simpleMap(Common.VENDORID, vendor.getId()),
                            OperateResult.OperateCategory.ResourceEvent, context));
                }
            }
        });
        return new BocloudResult<>(true, "任务已下发，正在执行...");
    }

    @Override
    public BocloudResult<List<Port>> ports(Long id, RequestContext context) {
        try {
            FloatingIp fip = floatingIpRepository.query(id);
            if (null == fip) {
                return new BocloudResult<>(false, "浮动IP不存在");
            }
            Map<Long, Port> portMap = Maps.newHashMap();
            Long projectId = context.getProject();
            List<Port> ports = null;
            // 如果是自服务端用户
            if (context.getCatalog().equals(Catalog.Tenant)) {
                // 租户能看到 1.属于当前租户的资源 2.租户下所有项目的资源
                List<Project> tenantProjects = smsProjectService.listTenantProjects(context.getTenant());
                List<Long> projectIds = tenantProjects.stream().map(Project::getId).collect(Collectors.toList());
                ports = portRepository.listAssociatePort(fip.getVendorId(), projectIds, null, context.getTenant());
            } else if (context.getCatalog().equals(Catalog.User)) {
                // 用户能看到 1.自己申请的资源 2.自己所在的资源可见项目（资源对项目下所有成员可见）下创建的资源 3.自己管理的项目下的资源
                List<Project> userManagerProjects = smsProjectService.listUserManagerProjects(context.getTarget());
                List<Project> visibleProjects = smsProjectService.listUserVisibleProjects(context.getTarget());
                List<Long> projectIds = new ArrayList<>();
                List<Long> userManagerProjectsIds =
                        userManagerProjects.stream().map(Project::getId).collect(Collectors.toList());
                if (!userManagerProjectsIds.isEmpty()) {
                    projectIds.addAll(userManagerProjectsIds);
                }
                List<Long> visibleProjectsIds =
                        visibleProjects.stream().map(Project::getId).collect(Collectors.toList());
                if (!visibleProjectsIds.isEmpty()) {
                    projectIds.addAll(visibleProjectsIds);
                }
                ports = portRepository.listAssociatePort(fip.getVendorId(), projectIds, context.getTarget(), null);
            } else {
                ports = portRepository.listAssociatePort(fip.getVendorId(), null, fip.getTenantUuid());
            }
            for (Port port : ports) {
                FloatingIp floatingIp = floatingIpRepository.getByPortId(port.getId());
                if (null != floatingIp) {
                    continue;
                }
                if (StringUtils.isEmpty(port.getDeviceName())) {
                    port.setName("None:" + port.getIpAddress());
                } else {
                    port.setName(port.getDeviceName() + ":" + port.getIpAddress());
                }
                portMap.put(port.getId(), port);
            }
            return new BocloudResult<>(true, new ArrayList<>(portMap.values()), "查询成功!");
        } catch (Exception e) {
            logger.error("list port failure:", e);
            return new BocloudResult<>(false, "查询失败!");
        }
    }

    @Override
    public BocloudResult apply(ApplicationParam param) {
        try {
            Assert.notNull(param, "参数格式错误");
            ServiceOrder order = param.getOrder();
            Assert.notNull(order, "订单不存在");
            List<OrderItem> items = order.getItems();
            Assert.notEmpty(items, "订单明细不存在");
            // 申请人
            RequestContext context = param.getContext();
            Assert.notNull(context, "申请人不存在");
            // 位置
            LocationModel location = param.getLocation();
            // 订购信息
            EmptionModel emption = param.getEmption();
            // 使用时长信息
            DurationModel duration = emption.getDuration();
            // 使用时长单位Hour/Month
            DurationModel.Mode mode = duration.getMode();
            // 时长
            Integer month = duration.getAmount();
            // 申请个数
            Integer count = null == emption.getCount() ? 1 : emption.getCount();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            if (DurationModel.Mode.Hour == mode) {
                calendar.setTime(DateTools.stringToDateTime("2099-12-31 00:00:00"));
            } else {
                calendar.add(Calendar.MONTH, month);
            }
            CloudVendor vendor = cloudVendorRepository.query(location.getVendorId());
            Assert.notNull(vendor, "当前可用域未绑定云平台");
            CloudProvider cloudProvider = CloudProvider.valueOf(vendor.getType());
            if (CloudProvider.ALIYUN == cloudProvider || CloudProvider.HUAWEI == cloudProvider
                    || CloudProvider.HCSO == cloudProvider || CloudProvider.AWS == cloudProvider) {
                return elasticIpService.apply(param);
            }
            if (CloudProvider.OPENSTACK == cloudProvider || CloudProvider.EASYSTACK == cloudProvider) {
                OSTenant osTenant = osTenantRepository.getByTenantId(context.getTenant(), vendor.getId());
                Assert.notNull(osTenant, "租户云平台认证信息不存在");
            }
            // 配置信息
            JSONObject configs = param.getConfigs();
            // networkId
            Long networkId = configs.getLong("networkId");
            String resourceLabel = configs.getString("resourceLabel");
            // 创建成功的IP
            List<BocloudResult> succList = Lists.newArrayList();
            // 创建失败的IP
            List<BocloudResult> failList = Lists.newArrayList();
            List<Future<BocloudResult>> futures = new ArrayList<>();
            for (int i = 0; i < count; i++) {
                OrderItem item = items.get(i);
                FloatingIp fIp = new FloatingIp();
                fIp.preSave(context.getTarget(), context.getTarget(), location.getVendorId(), networkId,
                        context.getTenant(), context.getProject());
                fIp.setOwnerId(context.getTarget());
                fIp.setUuid(item.getSn());
                fIp.setRegionId(location.getRegion());
                // 自服务需要用到
                fIp.setCreatorId(location.getCreatorId() == null ? 0 : location.getCreatorId());
                fIp.setOwnerId(location.getOwnerId() == null ? 0 : location.getOwnerId());
                fIp.setMenderId(location.getMenderId() == null ? 0 : location.getMenderId());
                fIp.setCatalog(context.getCatalog());
                fIp.setTenantId(context.getTenant() == null ? 0 : context.getTenant());
                fIp.setBusinessId(location.getBusinessId() == null ? 0 : location.getBusinessId());
                fIp.setProjectId(location.getProjectId() == null ? 0 : location.getProjectId());
                // 修改资源过期时间
                fIp.setExpiredTime(calendar.getTime());

                futures.add(taskExecutor.submit(() -> create(fIp, context)));
            }
            try {
                for (int i = 0; i < futures.size(); i++) {
                    List<ResourceModel> resources = new ArrayList<>();
                    OrderItem item = items.get(i);
                    // 通知订单
                    OrderMessage message = null;
                    BocloudResult result = futures.get(i).get(10, TimeUnit.MINUTES);
                    if (result.isSuccess()) {
                        FloatingIp floatingIp = (FloatingIp) result.getData();
                        // 自服务需要用到
                        floatingIp.setCreatorId(location.getCreatorId() == null ? 0 : location.getCreatorId());
                        floatingIp.setOwnerId(location.getOwnerId() == null ? 0 : location.getOwnerId());
                        floatingIp.setMenderId(location.getMenderId() == null ? 0 : location.getMenderId());
                        floatingIp.setCatalog(context.getCatalog());
                        floatingIp.setTenantId(context.getTenant() == null ? 0 : context.getTenant());
                        floatingIp.setBusinessId(location.getBusinessId() == null ? 0 : location.getBusinessId());
                        floatingIp.setProjectId(location.getProjectId() == null ? 0 : location.getProjectId());
                        // 修改资源过期时间
                        floatingIp.setExpiredTime(calendar.getTime());
                        floatingIp.setResourceLabel(resourceLabel);
                        floatingIpRepository.update(floatingIp);

                        ResourceEvent resourceEvent = new ResourceEvent(floatingIp.getId(), "浮动IP申请",
                                "浮动IP 【" + floatingIp.getFloatingIpAddress() + "】申请成功！", context.getTarget(), new Date(),
                                ResourceCategory.FloatingIp.name(), vendor.getId(), context.getCatalog());
                        resourceEvent.setResourceName(floatingIp.getFloatingIpAddress());
                        resourceEventRepository.save(resourceEvent);

                        BocloudResult bocloudResult = new BocloudResult<>(true,
                                "浮动IP【" + floatingIp.getFloatingIpAddress() + "】申请成功【" + result.getMessage() + "】");
                        succList.add(bocloudResult);
                        resources.add(new ResourceModel(floatingIp.getFloatingIpAddress(),
                                floatingIp.getFloatingIpUuid(), param.getService(), floatingIp.getFloatingIpUuid(), floatingIp.getUuid()));
                        message = new OrderMessage(item.getSn(), OrderMessage.Operation.Application,
                                OrderItemStatus.OpenedSuccess, null, bocloudResult.getMessage(), floatingIp.getGmtCreate(),
                                calendar.getTime(), resources, ResourceCategory.FloatingIp.name(), context);
                        message.setCategory(ResourceCategory.FloatingIp.name());
                        // 通知订单
                        amqpTemplate.convertAndSend("resource.result.queue", message);
                    } else {
                        BocloudResult bocloudResult =
                                new BocloudResult<>(false, "浮动IP申请失败：【" + result.getMessage() + "】");
                        failList.add(bocloudResult);
                        message = new OrderMessage(item.getSn(), OrderMessage.Operation.Application,
                                OrderItemStatus.OpenedFailure, null, result.getMessage(), null, null, resources,
                                ResourceCategory.FloatingIp.name(), context);
                        List<QuotaBean> quotas = new ArrayList<>();
                        quotas.add(new QuotaBean(param.getService(), 1));
                        quotas.add(new QuotaBean("meta.fip", 1));
                        message.setQuotas(quotas);
                        message.setCategory(ResourceCategory.FloatingIp.name());
                        // 通知订单
                        amqpTemplate.convertAndSend("resource.result.queue", message);
                    }
                }
            } catch (Exception e) {
                logger.error("apply floatingip fail:", e);
            }
            // 发送给云平台统计队列对云平台重新统计
            JSONObject jsonObject = new JSONObject();
            jsonObject.put(Common.VENDORID, vendor.getId());
            amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);
            logger.info("apply floatingip  end...");
            return new BocloudResult<>(true, "浮动IP申请成功");
        } catch (Exception e) {
            logger.error("Apply floatingip error：{}", e.getMessage());
            return new BocloudResult<>(false, e.getMessage());
        }

    }

    @Override
    public BocloudResult updateExpriedTime(Long resId, Integer months, RequestContext context) {
        String path = FloatingIp.class.getSimpleName() + "_" + resId;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            ObjectRelation relation = objectRelationRepository.get(resId, ResourceCategory.FloatingIp.name());
            if (null == relation) {
                return new BocloudResult<>(false, "查织机构资源实体信息失败!");
            }
            BocloudResult<User> userResult = smsUserService.detail(relation.getTarget());
            if (userResult.isFailed()) {
                return new BocloudResult<>(false, "申请人不存在，云IP延期失败");
            }
            User user = userResult.getData();
            if (null == user) {
                return new BocloudResult<>(false, "申请人不存在，云IP延期失败");
            }
            FloatingIp fip = floatingIpRepository.query(resId);
            if (null == fip) {
                return new BocloudResult<>(false, "云IP不存在");
            }
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(relation.getExpiredTime());
            calendar.add(Calendar.MONTH, months);
            boolean flag = objectRelationRepository.updateExpriedTime(resId, calendar.getTime(),
                    ResourceCategory.FloatingIp.name(), "USER");
            if (!flag) {
                return new BocloudResult<>(false, "云IP延期失败!");
            }
            return new BocloudResult<>(true, "云IP延期成功!");
        } catch (Exception e) {
            logger.error("update floating ip expried time fail:", e);
            return new BocloudResult<>(false, "云IP延期失败!");
        }
    }

    @Override
    public BocloudResult cancelation(CancelationParam param) {
        try {
            String service = param.getService();
            if ("network.aliyun.eip".equalsIgnoreCase(service) || "network.huawei.eip".equalsIgnoreCase(service)
                    || "network.aws.eip".equalsIgnoreCase(service)) {
                return elasticIpService.cancelation(param);
            }
            FloatingIp floatingIp = floatingIpRepository.getByUuid(param.getInstance());
            Assert.notNull(floatingIp, "浮动IP不存在");
            CloudVendor vendor = cloudVendorRepository.query(floatingIp.getVendorId());
            Assert.notNull(vendor, "云平台不存在！");
            CloudProvider cloudProvider = CloudProvider.valueOf(vendor.getType());
            RequestContext context = param.getContext();
            BocloudResult result = remove(floatingIp.getId(), context);
            Assert.isTrue(result.isSuccess(), result.getMessage());
            OrderMessage orderMessage = new OrderMessage(param.getInstance(), OrderMessage.Operation.Cancelation,
                    OrderItemStatus.UnsubscribeSuccess, null, "浮动IP退订成功", null, null, new ArrayList<>(),
                    ResourceCategory.FloatingIp.name(), context);
            orderMessage.setCategory(ResourceCategory.FloatingIp.name());
            List<QuotaBean> quotas = new ArrayList<>();
            CloudProvider provider = CloudProvider.valueOf(vendor.getType());
            switch (provider) {
                case OPENSTACK:
                    quotas.add(new QuotaBean("openstack.standard.eip", 1));
                    break;
                case MANAGEONE:
                    quotas.add(new QuotaBean("manageone.standard.eip", 1));
                    break;
                default:
                    break;
            }
            quotas.add(new QuotaBean("meta.fip", 1));
            orderMessage.setQuotas(quotas);
            amqpTemplate.convertAndSend("resource.result.queue", orderMessage);
            return new BocloudResult<>(true, "浮动IP退订成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e.getMessage());
            return new BocloudResult<>(false, e.getMessage());
        }
    }

    @Override
    public BocloudResult batchRemove(List<Long> ids, RequestContext context) {
        if (ListTool.isEmpty(ids)) {
            return new BocloudResult<>(false, "没有需要删除的快照！");
        }
        try {
            List<BocloudResult> succList = Lists.newArrayList();
            List<BocloudResult> failList = Lists.newArrayList();
            Long vendorId = null;
            for (Long id : ids) {
                FloatingIp floatingIp = floatingIpRepository.query(id);
                if (null != floatingIp) {
                    if (null == vendorId) {
                        vendorId = floatingIp.getVendorId();
                    }
                    BocloudResult result = remove(id, context);
                    if (result.isSuccess()) {
                        succList.add(new BocloudResult<>(true, "【" + floatingIp.getFloatingIpAddress() + "】删除成功"));
                    } else {
                        failList.add(new BocloudResult<>(false,
                                "【" + floatingIp.getFloatingIpAddress() + "】删除失败：" + result.getMessage()));
                    }
                }
            }
            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            String operate = vendor.getType().toLowerCase() + ".floatingIp";
            // 删除成功的数量
            int success = succList.size();
            // 删除失败的数量
            int fail = failList.size();
            String content = null;
            if (fail == ids.size()) {
                content = "浮动IP批量删除失败，详情如下：\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 = "浮动IP批量删除成功【" + 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 snapshot fail:", e);
            return new BocloudResult<>(false, "批量删除任务下发失败");
        }
        return new BocloudResult<>(true, "批量删除任务已下发，正在执行...");
    }

    @Override
    public BocloudResult count(Long userId, Long projectId, Long tenantId) {
        try {
            List<Param> params = Lists.newArrayList();
            Catalog catalog = Catalog.Tenant;
            Long target = tenantId;
            if (null != userId) {
                target = userId;
                catalog = Catalog.User;
            }
            List<Project> projects = smsProjectService.projectsByCondition(target, catalog);
            List<Long> projectIds = new ArrayList<>();
            // 此时查询的是全部用户全部项目的信息
            if (null != projectId && 0L != projectId) {
                projectIds.add(projectId);
            } else if (!ListTool.isEmpty(projects)) {
                projects.forEach(project -> projectIds.add(project.getId()));
            } else {
                // 当前用户不属于任何项目，则登录之后查看不到任何信息
                projectIds.add(-1L);
            }
            int total = floatingIpRepository.count(params, null, projectIds);
            return new BocloudResult<>(true, total, "查询成功");
        } catch (Exception e) {
            logger.error("Get error message：", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult associate(String params, RequestContext context) {
        try {
            JSONObject object = JSONObject.parseObject(params);
            if (null == object) {
                return new BocloudResult<>(false, "参数格式有误");
            }
            Long portId = object.getLong("portId");
            if (null != portId) {
                return associate(object.getLong("id"), portId, context.getTarget());
            }
            Long floatId = object.getLong("id");
            FloatingIp floatingIp = floatingIpRepository.query(floatId);
            if (null == floatingIp) {
                return new BocloudResult<>(false, "浮动IP不存在");
            }
            CloudVendor cloudVendor = cloudVendorRepository.query(floatingIp.getVendorId());
            if (null == cloudVendor) {
                return new BocloudResult<>(false, "平台信息不存在");
            }
            CloudProvider provider = CloudProvider.valueOf(cloudVendor.getType());
            FloatingIpModel floatingIpModel = new FloatingIpModel();
            floatingIpModel.setFloatingIpUuid(floatingIp.getFloatingIpUuid());
            floatingIpModel.setFloatingIpAddress(floatingIp.getFloatingIpAddress());
            floatingIpModel.setFixedIpAddress(object.getString("fixedIpAddress"));
            floatingIpModel.setInstanceId(object.getString("instanceId"));

            // 绑定云主机
            Long serverId = object.getLong("serverId");
            CloudServer cloudServer = null;
            if (null != serverId && serverId > 0) {
                cloudServer = cloudServerRepository.query(serverId);
                if (null == cloudServer) {
                    return new BocloudResult<>(false, "云主机不存在");
                }
                FloatingIp floatingIpByIns = floatingIpRepository.getByInstanceId(cloudServer.getInstanceId());
                if (floatingIpByIns != null) {
                    return new BocloudResult<>(false, "当前云主机已绑定浮动IP");
                }
                floatingIpModel.setInstanceId(cloudServer.getInstanceId());
            }
            // 绑定网卡
            Long networkCardId = object.getLong("networkCardId");
            NetworkCard networkCard = networkCardRepository.query(networkCardId);
            if (null != networkCard) {
                floatingIpModel.setRegionId(networkCard.getRegionId());
                floatingIpModel.setNetworkCardUuid(networkCard.getNetworkcardUuid());
                String ipAddress = networkCard.getIpAddress();
                if (null == ipAddress) {
                    return new BocloudResult<>(false, "地址解析错误");
                }
                JSONObject ipObject = JSON.parseObject(JSON.toJSONString(ipAddress), JSONObject.class);
                String privateIpAddress = ipObject.getString("privateIpAddress");
                floatingIpModel.setPrivateIpAddress(privateIpAddress);
            }
            if (CloudProvider.TIANYI.name().equals(cloudVendor.getType())) {
                cloudServer =
                        cloudServerRepository.getByInstanceId(floatingIpModel.getInstanceId(), cloudVendor.getId());
            }
            CloudServer server = cloudServer;
            new Thread(() -> {
                String content = "绑定失败";
                String operate = cloudVendor.getType().toLowerCase() + ".floatingip";
                Boolean resultFlag = false;
                try {
                    BocloudResult bocloudResult =
                            floatIPDriver.associate(cloudVendor.getUuid(), floatingIpModel, floatingIp.getRegionId());
                    if (bocloudResult.isSuccess()) {

                        String oldPubIp = "";
                        List<String> parseArray = JSON.parseArray(server.getPublicIps(), String.class);
                        if (null != parseArray && !parseArray.isEmpty()) {
                            oldPubIp = parseArray.get(0);
                        }
                        FloatingIpModel model =
                                JSON.parseObject(JSON.toJSONString(bocloudResult.getData()), FloatingIpModel.class);
                        floatingIp.setInstanceId(model.getInstanceId());
                        floatingIp.setNetworkCardUuid(model.getNetworkCardUuid());
                        floatingIp.setStatus(model.getStatus());
                        floatingIp.setGmtModify(new Date());
                        String privateIps = server.getPrivateIps();
                        switch (provider) {
                            case HUAWEI:
                            case HCSO:
                                List<JSONObject> ipObjects = JSONObject.parseArray(privateIps, JSONObject.class);
                                if (!ListTool.isEmpty(ipObjects)) {
                                    for (JSONObject ipObject : ipObjects) {
                                        String type = ipObject.getString("type");
                                        if ("fixed".equalsIgnoreCase(type)) {
                                            floatingIp.setFixedIpAddress(ipObject.getString("address"));
                                            break;
                                        }
                                    }
                                }
                                break;
                            case QCLOUD:
                                List<JSONObject> qcloudIpObjects = JSONObject.parseArray(privateIps, JSONObject.class);
                                if (!ListTool.isEmpty(qcloudIpObjects)) {
                                    floatingIp.setFixedIpAddress(qcloudIpObjects.get(0).getString("address"));
                                }
                                break;
                            default:
                                List<String> ips = JSONObject.parseArray(privateIps, String.class);
                                if (!ListTool.isEmpty(ips)) {
                                    floatingIp.setFixedIpAddress(ips.get(0));
                                }
                                break;
                        }
                        floatingIpRepository.update(floatingIp);
                        List<String> publicIps = JSON.parseArray(server.getPublicIps(), String.class);
                        if (null == publicIps) {
                            publicIps = Lists.newArrayList();
                        }
                        publicIps.add(floatingIp.getFloatingIpAddress());
                        server.setPublicIps(JSON.toJSONString(publicIps));
                        cloudServerRepository.update(server);
                        content = "绑定成功";

                        Resource resource = resourceRepository.query(ResourceCategory.Computer.name(),
                                ResourceCatalog.LOGICAL.name(), server.getId());
                        if (null != resource) {
                            List<String> ips = new ArrayList<>();
                            if (!StringUtils.isEmpty(resource.getPrivateIps())) {
                                List<String> objects = JSONObject.parseArray(resource.getPrivateIps(), String.class);
                                if (objects.contains(oldPubIp)) {
                                    objects.remove(oldPubIp);
                                }
                                ips.addAll(objects);
                            }
                            ips.add(floatingIp.getFloatingIpAddress());
                            resource.setPrivateIps(JSON.toJSONString(ips));
                            resourceRepository.update(resource);
                        }
                        resultFlag = true;

                    } else {
                        content = bocloudResult.getMessage();
                    }
                } catch (Exception e) {
                    logger.error("floatingip绑定失败 ： " + e);
                    content = e.getMessage();
                }
                resourceEventPublisher.send(new OperateResult(resultFlag, content, operate,
                        MapTools.simpleMap(Common.VENDORID, floatingIp.getVendorId()),
                        OperateResult.OperateCategory.ResourceEvent, context));
            }).start();
            return new BocloudResult<>(true, "绑定任务已下发...");
        } catch (Exception e) {
            logger.error("绑定异常：", e);
            return new BocloudResult<>(false, "绑定失败");
        }
    }

    @Override
    public BocloudResult extension(ExtensionParam param) {

        try {
            FloatingIp floatingIp = floatingIpRepository.getByUuid(param.getInstance());
            Assert.notNull(floatingIp, "浮动IP不存在");
            CloudVendor vendor = cloudVendorRepository.query(floatingIp.getVendorId());
            Assert.notNull(vendor, "云平台不存在！");
            CloudProvider cloudProvider = CloudProvider.valueOf(vendor.getType());
            if (CloudProvider.ALIYUN == cloudProvider || CloudProvider.HUAWEI == cloudProvider
                    || CloudProvider.HCSO == cloudProvider || CloudProvider.AWS == cloudProvider) {
                return elasticIpService.extension(param);
            }

            Calendar calendar = Calendar.getInstance();
            calendar.setTime(floatingIp.getExpiredTime());
            calendar.add(Calendar.MONTH, param.getExtension());
            floatingIp.setExpiredTime(calendar.getTime());
            floatingIpRepository.update(floatingIp);

            OrderMessage message = new OrderMessage();
            message.setSn(param.getInstance());
            message.setOperation(Operation.Extension);
            message.setStatus(OrderItemStatus.ExtensionSuccess);
            message.setExtension(param.getExtension());
            message.setExpiredTime(calendar.getTime());
            message.setCategory(ResourceCategory.FloatingIp.name());
            message.setMessage("浮动IP延期成功");
            amqpTemplate.convertAndSend("resource.result.queue", message);
            return new BocloudResult<>(true, "浮动IP延期成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e);
            return new BocloudResult<>(false, e.getMessage());
        }

    }
}
