package com.bocloud.ims.service.resource;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.entity.enums.ResourceCategory;
import com.bocloud.cmp.model.common.OrderItem;
import com.bocloud.cmp.model.common.OrderMessage;
import com.bocloud.cmp.model.common.OrderMessage.Operation;
import com.bocloud.cmp.model.common.ServiceOrder;
import com.bocloud.cmp.vm.model.ResourceAssignParam;
import com.bocloud.common.enums.ResourceCatalog;
import com.bocloud.common.model.*;
import com.bocloud.common.model.RequestContext.Catalog;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.DateTools;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.common.Project;
import com.bocloud.ims.entity.common.User;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.entity.resource.ResourceQuota.Action;
import com.bocloud.ims.interfaces.resource.ResourceAllocateService;
import com.bocloud.ims.interfaces.resource.ResourcePoolService;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.service.common.ShtermService;
import com.bocloud.ims.service.internal.CosInternalService;
import com.bocloud.ims.service.internal.ResourceOrderService;
import com.bocloud.ims.service.internal.SmsProjectService;
import com.bocloud.ims.service.internal.SmsUserService;
import com.bocloud.ims.service.utils.DateUtils;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.nms.enums.ChargeCommon;
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.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * 资源分配给项目service接口实现
 *
 * @author wangyu
 * @version 4.1.0-SNAPSHOT
 * @since 2019/2/28
 */
@Service("resourceAllocateService")
public class ResourceAllocateServiceImpl implements ResourceAllocateService {

    private static Logger logger = LoggerFactory.getLogger(ResourceAllocateServiceImpl.class);

    public static final String TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private VolumeRepository volumeRepository;
    @Autowired
    private SnapshotRepository snapshotRepository;
    @Autowired
    private ImageRepository imageRepository;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private ObjectRelationRepository objectRelationRepository;
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private FloatingIpRepository floatingIpRepository;
    @Autowired
    private SmsProjectService smsProjectService;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private CosInternalService cosInternalService;
    @Autowired
    private ResourceOrderService resourceOrderService;
    @Autowired
    private NetworkInterfaceRepository networkInterfaceRepository;
    @Autowired
    private VpcRepository vpcRepository;
    @Autowired
    private ElasticIpRepository elasticIpRepository;
    @Autowired
    private NetworkRepository networkRepository;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private LoadBalancerRepository loadBalancerRepository;
    @Autowired
    private SecurityGroupRepository securityGroupRepository;
    @Autowired
    private ResourcePoolService resourcePoolService;
    @Autowired
    private OSTenantRepository osTenantRepository;
    @Autowired
    private TenantNetworkRepository tenantNetworkRepository;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private SmsUserService smsUserService;

    @Override
    public BocloudResult assign(JSONObject object, ResourceCategory category, RequestContext context) {
        // 资源ID
        List<Long> serverIds = JSON.parseArray(object.getString("ids"), Long.class);
        if (ListTool.isEmpty(serverIds)) {
            return new BocloudResult<>(false, "无资源分配");
        }
        // 租户用户ID
        final Long userId = object.getLong("userId");
        // 租户用户所在项目
        final Long projectId = object.getLong("projectId") == null ? 0L : object.getLong("projectId");
        // 租户ID
        Long resourceTenantId = object.getLong("tenantId") == null ? 0L : object.getLong("tenantId");
        // 业务ID
        Long businessId = object.getLong("businessId") == null ? 0L : object.getLong("businessId");
        // 租户ID集合
        List<Long> tenantIds = JSON.parseArray(object.getString("tenantIds"), Long.class);
        if (resourceTenantId == 0 && projectId != 0) {
            BocloudResult<Project> bocloudResult = smsProjectService.detail(projectId);
            if (bocloudResult.isFailed()) {
                return bocloudResult;
            }
            Project project = bocloudResult.getData();
            resourceTenantId = project.getTenantId();
        }
        if (projectId != 0 && businessId == 0) {
            BocloudResult<Project> bocloudResult = smsProjectService.detail(projectId);
            if (bocloudResult.isFailed()) {
                return bocloudResult;
            }
            Project project = bocloudResult.getData();
            if (businessId == 0L && project!= null) {
                businessId = project.getBusinessId();
            }
        }
        if (null == category) {
            return new BocloudResult<>(false, "资源类型错误");
        }
        final Long tenantId = resourceTenantId;
        final Long finalBusinessId = businessId;
        Long finalBusinessId1 = businessId;
        new Thread(new Runnable() {
            @Override
            public void run() {
                String path = null;
                CloudVendor vendor = null;
                BocloudResult result = null;
                try (BocloudACLock tenantLock = lockFactory.getACLock(CloudServer.class.getSimpleName() + "_assign_" + tenantId)){
                    Assert.isTrue(tenantLock.acquire(10, TimeUnit.MINUTES), "请求超时");
                    for (Long id : serverIds) {
                        List<ResourceQuota> quotas = new ArrayList<>();
                        // 生成的订单
                        List<ServiceOrder> orders = new ArrayList<>();
                        // 生成的订单明细
                        List<OrderItem> items = new ArrayList<>();
                        switch (category) {
                            case Computer:
                                path = CloudServer.class.getSimpleName() + "_" + id;
                                try (BocloudACLock lock = lockFactory.getACLock(path)) {
                                    Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                                    CloudServer server = cloudServerRepository.query(id);
                                    Assert.notNull(server, "云主机不存在");
                                    vendor = cloudVendorRepository.query(server.getVendorId());
                                    Assert.notNull(vendor, "云平台不存在");
                                    Long serverTenantId = server.getTenantId();
                                    if (null != serverTenantId && serverTenantId != 0) {
                                        if (serverTenantId == tenantId) {
                                            // 自服务需要用到
                                            server.setOwnerId(userId);
                                            server.setBusinessId(finalBusinessId1);
                                            server.setMenderId(userId);
                                            server.setCatalog(Catalog.User);
                                            server.setTenantId(tenantId);
                                            server.setRecycle(false);
                                            server.setProjectId(projectId);
                                            cloudServerRepository.update(server);
                                            //这里只做资源归属的修改不更新订单
                                            sendNotice(true, "资源【" + server.getName() + "】分配成功", context);
                                            return;
                                        }else {
                                            sendNotice(false, "资源【" + server.getName() + "】属于租户资源，不允许再次分配", context);
                                            return;
                                        }
                                    }
                                    // op校验项目
                                    if (CloudProvider.OPENSTACK.name().equalsIgnoreCase(vendor.getType())
                                            || CloudProvider.HCSO.name().equalsIgnoreCase(vendor.getType())) {
                                        OSTenant osTenant = osTenantRepository.getByTenantId(tenantId, vendor.getId());
                                        if (null == osTenant
                                                || !osTenant.getTenantUuid().equalsIgnoreCase(server.getTenantUuid())) {
                                            sendNotice(false, "资源【" + server.getName() + "】所属项目与该租户暂无关联关系，分配失败", context);
                                            return;
                                        }
                                    }
                                    Integer cpu = server.getCpu();
                                    BigDecimal memory = server.getMemory();
                                    Integer disk = 0;
                                    Integer eip = 0;
                                    FloatingIp floatingIp = null;
                                    ElasticIp elasticIp = null;

                                    String serverServiceCode = getVmServiceCode(vendor);
                                    String eipServiceCode = getEipServiceCode(vendor);
                                    String volumeServiceCode = getVolumeServiceCode(vendor);

                                    // 根据平台获取浮动IP
                                    if (CloudProvider.ALIYUN.name().equals(server.getVendorType())) {
                                        List<ElasticIp> elasticIps = elasticIpRepository.listByIid(server.getInstanceId(),
                                                server.getVendorId());
                                        if (!ListTool.isEmpty(elasticIps)) {
                                            elasticIp = elasticIps.get(0);
                                            eip = 1;
                                        }
                                    } else if (CloudProvider.HUAWEI.name().equals(server.getVendorType())
                                            || CloudProvider.HCSO.name().equals(server.getVendorType())) {
                                        elasticIp = elasticIpRepository.queryByAllocationId(server.getInstanceId());
                                        if (null != elasticIp) {
                                            eip = 1;
                                        }
                                    } else if (CloudProvider.TENCENT.name().equals(server.getVendorType())
                                            || CloudProvider.QCLOUD.name().equals(server.getVendorType())) {
                                        floatingIp = floatingIpRepository.listByInstanceId(server.getInstanceId(),
                                                server.getVendorId());
                                        if (null != floatingIp) {
                                            eip = 1;
                                        }
                                    } else {
                                        floatingIp = floatingIpRepository.listByServerId(server.getInstanceId());
                                        if (null != floatingIp) {
                                            eip = 1;
                                        }
                                    }

                                    List<Volume> volumes = volumeRepository.listByServerId(server.getId());
                                    List<Snapshot> snapshots = new ArrayList<>();
                                    if (!ListTool.isEmpty(volumes)) {
                                        Long volumeCount = 0L;
                                        for (Volume volume : volumes) {
                                            volumeCount += 1;
                                            // 磁盘总量
                                            Integer size = volume.getSize();
                                            if (null != size) {
                                                disk = disk + size;
                                            }
                                            // 磁盘的快照
                                            Pager pager = new Pager(1, Integer.MAX_VALUE, new ArrayList<>(), new HashMap<>());
                                            List<Snapshot> volumeSnapshots = snapshotRepository.listByVolumeId(volume.getId(), pager);
                                            if (!ListTool.isEmpty(volumeSnapshots)) {
                                                snapshots.addAll(volumeSnapshots);
                                            }
                                        }
                                        if (!CloudProvider.VMWARE.name().equals(server.getVendorType())) {
                                            quotas.add(new ResourceQuota(volumeServiceCode, volumeCount));
                                        }
                                    }
                                    // vc获取快照信息
                                    if (CloudProvider.VMWARE.name().equals(server.getVendorType())) {
                                        List<Snapshot> vcSnaps = snapshotRepository.listByVMid(server.getId());
                                        if(!ListTool.isEmpty(vcSnaps)) {
                                            snapshots.addAll(vcSnaps);
                                        }
                                    }

                                    if (!ListTool.isEmpty(snapshots)) {
                                        quotas.add(new ResourceQuota("meta.snapshot", Long.valueOf(snapshots.size())));
                                    }
                                    quotas.add(new ResourceQuota("meta.cpu", Long.valueOf(cpu)));
                                    quotas.add(new ResourceQuota("meta.mem", memory.longValue()));
                                    quotas.add(new ResourceQuota("meta.disk", Long.valueOf(disk)));
                                    quotas.add(new ResourceQuota(serverServiceCode, 1L));
                                    if (eip != 0) {
                                        quotas.add(new ResourceQuota(eipServiceCode, Long.valueOf(eip)));
                                    }
                                    // 更新配额
                                    result = cosInternalService.updateQuotas(quotas, Action.Order, tenantId);
                                    Assert.isTrue(result.isSuccess(), result.getMessage());
                                    // 生成云主机订单
                                    BocloudResult createOrder = resourceOrderService.createOrder(vendor.getId(),
                                            serverServiceCode, tenantId, userId, true, projectId);
                                    if (createOrder.isFailed()) {
                                        // 回滚配额
                                        callback(orders, items, tenantId, quotas);
                                        sendNotice(false, "分配云主机发生错误：" + createOrder.getMessage(), context);
                                        return;
                                    }
                                    ServiceOrder vmOrder = JSONObject.parseObject(
                                            JSONObject.toJSONString(createOrder.getData()), ServiceOrder.class);
                                    if (null == vmOrder) {
                                        // 回滚配额
                                        callback(orders, items, tenantId, quotas);
                                        sendNotice(false, "分配云主机失败：" + result.getMessage(), context);
                                        return;
                                    }
                                    orders.add(vmOrder);
                                    result = assignServer(vendor, server, userId, tenantId, projectId, items,
                                            vmOrder.getId(), serverServiceCode, finalBusinessId);
                                    if (result.isFailed()) {
                                        // 回收云主机
                                        recycleServer(server, vendor, context, false);
                                        callback(orders, items, tenantId, quotas);
                                        sendNotice(false, "分配云主机失败：" + result.getMessage(), context);
                                        return;
                                    }
                                    // 磁盘
                                    if (!ListTool.isEmpty(volumes)) {
                                        result = assignVolume(vendor, userId, tenantId, projectId, volumes, items,
                                                vmOrder.getId(), volumeServiceCode, finalBusinessId);
                                        if (result.isFailed()) {
                                            // 回收云主机
                                            recycleServer(server, vendor, context, false);
                                            // 更新云硬盘
                                            recycleVolume(volumes, context, false);
                                            callback(orders, items, tenantId, quotas);
                                            sendNotice(false, "分配云主机失败：" + result.getMessage(), context);
                                            return;
                                        }
                                    }
                                    if (!ListTool.isEmpty(snapshots)) {
                                        result = assignSnapshot(userId, tenantId, projectId, snapshots, finalBusinessId);
                                        if (result.isFailed()) {
                                            // 回收云主机
                                            recycleServer(server, vendor, context, false);
                                            // 更新云硬盘
                                            recycleVolume(volumes, context, false);
                                            recycleSnapshot(snapshots, context, false);
                                            callback(orders, items, tenantId, quotas);
                                            sendNotice(false, "分配云主机失败：" + result.getMessage(), context);
                                            return;
                                        }
                                    }
                                    // 浮动IP
                                    if (null != floatingIp) {
                                        // 生成云主机订单
                                        BocloudResult createFipOrder = resourceOrderService.createOrder(vendor.getId(),
                                                eipServiceCode, tenantId, userId, true, projectId);
                                        if (createFipOrder.isFailed()) {
                                            // 更新云主机
                                            recycleServer(server, vendor, context, false);
                                            // 更新云硬盘
                                            recycleVolume(volumes, context, false);
                                            recycleSnapshot(snapshots, context, false);
                                            callback(orders, items, tenantId, quotas);
                                            sendNotice(false, "分配云主机发生错误：下单失败," + createFipOrder.getMessage(), context);
                                            return;
                                        }
                                        ServiceOrder fipOrder = JSONObject.parseObject(
                                                JSONObject.toJSONString(createFipOrder.getData()), ServiceOrder.class);
                                        if (null == fipOrder) {
                                            // 更新云主机
                                            recycleServer(server, vendor, context, false);
                                            // 更新云硬盘
                                            recycleVolume(volumes, context, false);
                                            recycleSnapshot(snapshots, context, false);
                                            callback(orders, items, tenantId, quotas);
                                            sendNotice(false, "分配云主机失败：" + result.getMessage(), context);
                                            return;
                                        }
                                        orders.add(fipOrder);
                                        result = assignFloatingIp(vendor, userId, tenantId, projectId, floatingIp, items,
                                                fipOrder.getId(), eipServiceCode, finalBusinessId);
                                        if (result.isFailed()) {
                                            // 更新云主机
                                            recycleServer(server, vendor, context, false);
                                            // 更新云硬盘
                                            recycleVolume(volumes, context, false);
                                            // 回收浮动IP
                                            recycleFloatingIp(floatingIp, context, false);
                                            recycleSnapshot(snapshots, context, false);
                                            callback(orders, items, tenantId, quotas);
                                            sendNotice(false, "分配云主机发生错误：下单失败," + result.getMessage(), context);
                                            return;
                                        }
                                    }
                                    if (null != elasticIp) {
                                        // 生成云主机订单

                                        BocloudResult createElasticIpOrder = resourceOrderService.createOrder(
                                                vendor.getId(), eipServiceCode, tenantId, userId, true, projectId);
                                        if (createElasticIpOrder.isFailed()) {
                                            callback(orders, items, tenantId, quotas);
                                            // 更新云主机
                                            recycleServer(server, vendor, context, false);
                                            // 更新云硬盘
                                            recycleVolume(volumes, context, false);
                                            recycleSnapshot(snapshots, context, false);
                                            sendNotice(false, "分配云主机失败：" + result.getMessage(), context);
                                            return;
                                        }
                                        ServiceOrder fipOrder = JSONObject.parseObject(
                                                JSONObject.toJSONString(createElasticIpOrder.getData()),
                                                ServiceOrder.class);
                                        if (null == fipOrder) {
                                            callback(orders, items, tenantId, quotas);
                                            // 更新云主机
                                            recycleServer(server, vendor, context, false);
                                            // 更新云硬盘
                                            recycleVolume(volumes, context, false);
                                            recycleSnapshot(snapshots, context, false);
                                            sendNotice(false, "分配云主机发生错误：订单生成失败", context);
                                            return;
                                        }
                                        orders.add(fipOrder);
                                        result = assignElasticIp(vendor, userId, tenantId, projectId, elasticIp, items,
                                                fipOrder.getId(), eipServiceCode, finalBusinessId);
                                        if (result.isFailed()) {
                                            // 更新云主机
                                            recycleServer(server, vendor, context, false);
                                            // 更新云硬盘
                                            recycleVolume(volumes, context, false);
                                            recycleSnapshot(snapshots, context, false);
                                            // 回收浮动IP
                                            recycleElasticIp(elasticIp, context, false);
                                            callback(orders, items, tenantId, quotas);
                                            sendNotice(false, "分配云主机失败：" + result.getMessage(), context);
                                            return;
                                        }
                                    }
                                } catch (Exception e) {
                                    logger.info("资源分配失败租户ID：【{}】,用户ID：【{}】,项目ID【{}】,业务ID：【{}】",tenantId, userId, projectId, finalBusinessId);
                                    logger.error("Get error message：{}", e);
                                    sendNotice(false, e.getMessage(), context);
                                    return;
                                }
                                break;
                            case Storage:
                                Volume volume = volumeRepository.query(id);
                                if (null == volume) {
                                    sendNotice(false, "云硬盘不存在", context);
                                    return;
                                }
                                vendor = cloudVendorRepository.query(volume.getVendorId());
                                Assert.notNull(vendor, "云平台不存在");
                                Long volumeTenantId = volume.getTenantId();
                                if (null != volumeTenantId && volumeTenantId != 0) {
                                    sendNotice(false, "资源【" + volume.getName() + "】属于租户资源，不允许再次分配", context);
                                    return;
                                }
                                // op校验项目
                                if (CloudProvider.OPENSTACK.name().equalsIgnoreCase(vendor.getType())
                                        || CloudProvider.HCSO.name().equalsIgnoreCase(vendor.getType())) {
                                    OSTenant osTenant = osTenantRepository.getByTenantId(tenantId, vendor.getId());
                                    if (null == osTenant
                                            || !osTenant.getTenantUuid().equalsIgnoreCase(volume.getTenantUuid())) {
                                        sendNotice(false, "资源【" + volume.getName() + "】所属项目与该租户暂无关联关系，分配失败", context);
                                        return;
                                    }
                                }
                                String storageServiceCode = getVolumeServiceCode(vendor);
                                quotas.add(new ResourceQuota("meta.disk", Long.valueOf(volume.getSize())));
                                quotas.add(new ResourceQuota(storageServiceCode, 1L));
                                String snapshotServiceCode = "meta.snapshot";
                                Pager pager = new Pager(1, Integer.MAX_VALUE, new ArrayList<>(), new HashMap<>());
                                List<Snapshot> snapshots = snapshotRepository.listByVolumeId(id, pager);
                                if (!ListTool.isEmpty(snapshots)) {
                                    quotas.add(new ResourceQuota(snapshotServiceCode, Long.valueOf(snapshots.size())));
                                }
                                result = cosInternalService.updateQuotas(quotas, Action.Order, tenantId);
                                Assert.isTrue(result.isSuccess(), result.getMessage());
                                List<Volume> volumes = Lists.newArrayList();
                                volumes.add(volume);
                                // 生成云主机订单
                                BocloudResult createDiskOrder = resourceOrderService.createOrder(vendor.getId(),
                                        storageServiceCode, tenantId, userId, true, projectId);
                                if (createDiskOrder.isFailed()) {
                                    // 更新云硬盘
                                    recycleVolume(volumes, context, false);
                                    callback(orders, items, tenantId, quotas);
                                    sendNotice(false, "分配云硬盘失败: 下单失败", context);
                                    return;
                                }
                                ServiceOrder diskOrder = JSONObject.parseObject(
                                        JSONObject.toJSONString(createDiskOrder.getData()), ServiceOrder.class);
                                if (null == diskOrder) {
                                    // 更新云硬盘
                                    recycleVolume(volumes, context, false);
                                    callback(orders, items, tenantId, quotas);
                                    sendNotice(false, "分配云硬盘失败: 下单失败", context);
                                    return;
                                }
                                orders.add(diskOrder);
                                result = assignVolume(vendor, userId, tenantId, projectId, volumes, items,
                                        diskOrder.getId(), storageServiceCode, finalBusinessId);
                                if (result.isFailed()) {
                                    // 更新云硬盘
                                    recycleVolume(volumes, context, false);
                                    callback(orders, items, tenantId, quotas);
                                    sendNotice(false, "分配云硬盘失败：" + result.getMessage(), context);
                                    return;
                                }
                                if (!ListTool.isEmpty(snapshots)) {
                                    result = assignSnapshot(userId, tenantId, projectId, snapshots, finalBusinessId);
                                    if (result.isFailed()) {
                                        // 更新云硬盘
                                        recycleVolume(volumes, context, false);
                                        // 回收云快照
                                        recycleSnapshot(snapshots, context, false);
                                        callback(orders, items, tenantId, quotas);
                                        sendNotice(false, "分配云硬盘失败：" + result.getMessage(), context);
                                        return;
                                    }
                                }
                                break;
                            case Vpc:
                                path = Vpc.class.getSimpleName() + "_" + id;
                                try (BocloudACLock lock = lockFactory.getACLock(path)) {
                                    Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                                    Vpc vpc = vpcRepository.query(id);
                                    Assert.notNull(vpc, "VPC数据不存在");
                                    vendor = cloudVendorRepository.query(vpc.getVendorId());
                                    Assert.notNull(vendor, "云平台不存在");

                                    String vpcServiceCode = getVpcServiceCode(vendor);
                                    quotas.add(new ResourceQuota(vpcServiceCode, 1L));
                                    result = cosInternalService.updateQuotas(quotas, Action.Order, tenantId);
                                    if (result.isFailed()) {
                                        if (CloudProvider.OPENSTACK.name().equals(vendor.getType()) || CloudProvider.EASYSTACK.name().equals(vendor.getType())) {
                                            vpcRepository.delete(id);
                                        }
                                        sendNotice(false, "VPC分配失败：" + result.getMessage(), context);
                                        return;
                                    }

                                    BocloudResult createVpcOrder = resourceOrderService.createOrder(vpc.getVendorId(),
                                            vpcServiceCode, tenantId, userId, null, projectId);
                                    if (createVpcOrder.isFailed()) {
                                        callback(orders, items, tenantId, quotas);
                                        sendNotice(false, "VPC分配失败：下单失败", context);
                                        return;
                                    }
                                    ServiceOrder vpcOrder = JSONObject.parseObject(
                                            JSONObject.toJSONString(createVpcOrder.getData()), ServiceOrder.class);
                                    if (null == vpcOrder) {
                                        callback(orders, items, tenantId, quotas);
                                        sendNotice(false, "VPC分配失败：订单生成失败，请联系管理员", context);
                                        return;
                                    }
                                    orders.add(vpcOrder);
                                    result = assignVpc(vendor, userId, tenantId, projectId, vpc, items, vpcOrder.getId(),
                                            vpcServiceCode, finalBusinessId);
                                    if (result.isFailed()) {
                                        // 回收VPC
                                        recycleVpc(vpc, context);
                                        callback(orders, items, tenantId, quotas);
                                        if (CloudProvider.OPENSTACK.name().equals(vendor.getType()) || CloudProvider.EASYSTACK.name().equals(vendor.getType())) {
                                            vpcRepository.delete(id);
                                        }
                                        sendNotice(false, "分配VPC失败：" + result.getMessage(), context);
                                        return;
                                    }
                                    // 如果当前网络所属的项目与租户没有关联关系 将该项目授权给租户
                                    if (CloudProvider.OPENSTACK.name().equals(vendor.getType()) || CloudProvider.EASYSTACK.name().equals(vendor.getType())) {
                                        Long networkId = vpc.getNetworkId();
                                        Network network = networkRepository.query(networkId);
                                        if (null != network) {
                                            Boolean shared = network.getShared() == null ? false : network.getShared();
                                            if (!shared) {
                                                OSTenant osTenant = osTenantRepository
                                                        .getByTenantUuid(network.getTenantUuid(), vendor.getId());
                                                if (null != osTenant) {
                                                    osTenant.setTenantId(tenantId);
                                                    osTenantRepository.update(osTenant);
                                                }
                                            }
                                            TenantNetwork entity = new TenantNetwork();
                                            entity.setNetworkId(networkId);
                                            entity.setTenantId(tenantId);
                                            entity.setVendorId(network.getVendorId());
                                            tenantNetworkRepository.save(entity);
                                            network.setTenantId(tenantId);
                                            networkRepository.update(network);
                                        }
                                    }
                                    // 如果当前VPC属于阿里云 则自动将vpc下的安全组分配过去
                                    if (CloudProvider.ALIYUN.name().equals(vendor.getType())) {
                                        List<SecurityGroup> securityGroups = securityGroupRepository
                                                .listByVpcId(vpc.getId(), null);
                                        if (!ListTool.isEmpty(securityGroups)) {
                                            List<Long> securityGroupIds = securityGroups.stream().map(SecurityGroup::getId)
                                                    .collect(Collectors.toList());
                                            object.put("ids", securityGroupIds);
                                            object.put("resourceCategory", ResourceCategory.SecurityGroup);
                                            assign(object, ResourceCategory.SecurityGroup, context);
                                        }
                                    }
                                } catch (Exception e) {
                                    logger.error("Get error message：{}", e);
                                    sendNotice(false, "分配VPC失败：" + e.getMessage(), context);
                                    return;
                                }
                                break;
                            case Network:
                                path = Network.class.getSimpleName() + "_" + id;
                                try (BocloudACLock lock = lockFactory.getACLock(path)) {
                                    Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                                    Network network = networkRepository.query(id);
                                    Assert.notNull(network, "网络数据不存在");
                                    vendor = cloudVendorRepository.query(network.getVendorId());
                                    Assert.notNull(vendor, "云平台不存在");
                                    // op校验项目
                                    if (CloudProvider.OPENSTACK.name().equalsIgnoreCase(vendor.getType())) {
                                        OSTenant osTenant = osTenantRepository.getByTenantId(tenantId, vendor.getId());
                                        if (null == osTenant
                                                || !osTenant.getTenantUuid().equalsIgnoreCase(network.getTenantUuid())) {
                                            sendNotice(false, "资源【" + network.getName() + "】所属项目与该租户暂无关联关系，分配失败", context);
                                            return;
                                        }
                                    }
                                    Vpc vpc = new Vpc();
                                    vpc.setVendorId(network.getVendorId());
                                    vpc.setRegionId(network.getRegionId());
                                    vpc.setExpiredTime(DateTools.stringToDateTime("2099-12-31 00:00:00"));
                                    // 自服务需要用到
                                    vpc.setOwnerId(userId);
                                    vpc.setMenderId(userId);
                                    vpc.setCatalog(Catalog.User);
                                    vpc.setTenantId(tenantId);
                                    vpc.setProjectId(projectId);
                                    vpc.setName(network.getName());
                                    vpc.setNetworkId(network.getId());
                                    vpc.setAssgined(true);
                                    vpc.setBusinessId(finalBusinessId);
                                    vpcRepository.save(vpc);

                                    List<Long> vpcIds = new ArrayList<>();
                                    vpcIds.add(vpc.getId());
                                    object.put("ids", vpcIds);
                                    object.put("resourceCategory", ResourceCategory.Vpc);
                                    BocloudResult assign = assign(object, ResourceCategory.Vpc, context);
                                    if (assign.isFailed()) {
                                        sendNotice(false, "网络分配失败：" + assign.getMessage(), context);
                                        return;
                                    }
                                } catch (Exception e) {
                                    logger.error("Get error message：{}", e);
                                    sendNotice(false, "网络分配失败：" + e.getMessage(), context);
                                    return;
                                }
                            case FloatingIp:
                                String vendorType = object.getString("vendorType");
                                CloudProvider cloudProvider = CloudProvider.valueOf(vendorType);
                                FloatingIp floatingIp = null;
                                ElasticIp elasticIp = null;
                                if (CloudProvider.ALIYUN == cloudProvider || CloudProvider.HUAWEI == cloudProvider
                                        || CloudProvider.AWS == cloudProvider) {
                                    elasticIp = elasticIpRepository.query(id);
                                } else {
                                    floatingIp = floatingIpRepository.query(id);
                                    // op校验项目
                                    if (CloudProvider.OPENSTACK.name().equalsIgnoreCase(vendorType)
                                            || CloudProvider.HCSO.name().equalsIgnoreCase(vendorType)) {
                                        OSTenant osTenant = osTenantRepository.getByTenantId(tenantId, floatingIp.getVendorId());
                                        if (null == osTenant
                                                || !osTenant.getTenantUuid().equalsIgnoreCase(floatingIp.getTenantUuid())) {
                                            sendNotice(false, "资源【" + floatingIp.getName() + "】所属项目与该租户暂无关联关系，分配失败", context);
                                            return;
                                        }
                                    }
                                }
                                String eipServiceCode = "";
                                // 浮动IP
                                if (null != floatingIp) {
                                    vendor = cloudVendorRepository.query(floatingIp.getVendorId());
                                    eipServiceCode = getEipServiceCode(vendor);
                                    quotas.add(new ResourceQuota(eipServiceCode, 1L));
                                    result = cosInternalService.updateQuotas(quotas, Action.Order, tenantId);
                                    Assert.isTrue(result.isSuccess(), result.getMessage());
                                    // 生成云主机订单

                                    BocloudResult createVpcOrder = resourceOrderService.createOrder(vendor.getId(),
                                            eipServiceCode, tenantId, userId, true, projectId);
                                    if (createVpcOrder.isFailed()) {
                                        sendNotice(false, "浮动IP分配失败：下单失败", context);
                                        return;
                                    }
                                    ServiceOrder fipOrder = JSONObject.parseObject(
                                            JSONObject.toJSONString(createVpcOrder.getData()), ServiceOrder.class);
                                    if (null == fipOrder) {
                                        sendNotice(false, "分配浮动IP发生错误：订单生成失败", context);
                                        return;
                                    }
                                    orders.add(fipOrder);
                                    result = assignFloatingIp(vendor, userId, tenantId, projectId, floatingIp, items,
                                            fipOrder.getId(), eipServiceCode, finalBusinessId);
                                    if (result.isFailed()) {
                                        callback(orders, items, tenantId, quotas);
                                        sendNotice(false, "分配浮动IP失败：" + result.getMessage(), context);
                                        return;
                                    }
                                }
                                if (null != elasticIp) {
                                    vendor = cloudVendorRepository.query(elasticIp.getVendorId());
                                    eipServiceCode = getEipServiceCode(vendor);
                                    quotas.add(new ResourceQuota(eipServiceCode, 1L));
                                    result = cosInternalService.updateQuotas(quotas, Action.Order, tenantId);
                                    Assert.isTrue(result.isSuccess(), result.getMessage());
                                    // 生成云主机订单
                                    BocloudResult createFipOrder = resourceOrderService.createOrder(vendor.getId(),
                                            eipServiceCode, tenantId, userId, true, projectId);
                                    if (createFipOrder.isFailed()) {
                                        sendNotice(false, "分配浮动IP失败：下单失败", context);
                                        return;
                                    }
                                    ServiceOrder fipOrder = JSONObject.parseObject(
                                            JSONObject.toJSONString(createFipOrder.getData()), ServiceOrder.class);
                                    if (null == fipOrder) {
                                        sendNotice(false, "分配浮动IP发生错误：订单生成失败", context);
                                        return;
                                    }
                                    orders.add(fipOrder);
                                    result = assignElasticIp(vendor, userId, tenantId, projectId, elasticIp, items,
                                            fipOrder.getId(), eipServiceCode, finalBusinessId);
                                    if (result.isFailed()) {
                                        callback(orders, items, tenantId, quotas);
                                        sendNotice(false, "分配浮动IP失败：" + result.getMessage(), context);
                                        return;
                                    }
                                }
                                break;
                            case LoadBalance:
                                path = LoadBalancer.class.getSimpleName() + "_" + id;
                                try (BocloudACLock lock = lockFactory.getACLock(path)) {
                                    Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                                    LoadBalancer loadBalancer = loadBalancerRepository.query(id);
                                    Assert.notNull(loadBalancer, "负载均衡数据不存在");
                                    vendor = cloudVendorRepository.query(loadBalancer.getVendorId());
                                    Assert.notNull(vendor, "云平台不存在");
                                    // op校验项目
                                    if (CloudProvider.OPENSTACK.name().equalsIgnoreCase(vendor.getType())
                                            || CloudProvider.HCSO.name().equalsIgnoreCase(vendor.getType())) {
                                        OSTenant osTenant = osTenantRepository.getByTenantId(tenantId, vendor.getId());
                                        if (null == osTenant
                                                || !osTenant.getTenantUuid().equalsIgnoreCase(loadBalancer.getTenantUuid())) {
                                            sendNotice(false, "资源【" + loadBalancer.getName() + "】所属项目与该租户暂无关联关系，分配失败", context);
                                            return;
                                        }
                                    }
                                    String slbServiceCode = getSlbServiceCode(vendor);
                                    quotas.add(new ResourceQuota(slbServiceCode, 1L));
                                    result = cosInternalService.updateQuotas(quotas, Action.Order, tenantId);
                                    Assert.isTrue(result.isSuccess(), result.getMessage());

                                    BocloudResult createSlbOrder = resourceOrderService.createOrder(id, slbServiceCode,
                                            tenantId, userId, null, projectId);
                                    if (createSlbOrder.isFailed()) {
                                        sendNotice(false, "负载均衡分配失败：下单失败", context);
                                        return;
                                    }
                                    ServiceOrder slbOrder = JSONObject.parseObject(
                                            JSONObject.toJSONString(createSlbOrder.getData()), ServiceOrder.class);
                                    if (null == slbOrder) {
                                        sendNotice(false, "负载均衡分配失败：订单生成失败，请联系管理员", context);
                                        return;
                                    }
                                    orders.add(slbOrder);
                                    result = assignLoadBalance(vendor, userId, tenantId, projectId, loadBalancer, items,
                                            slbOrder.getId(), slbServiceCode, finalBusinessId);
                                    if (result.isFailed()) {
                                        // 回收lb
                                        callback(orders, items, tenantId, quotas);
                                        sendNotice(false, "负载均衡分配失败：" + result.getMessage(), context);
                                        return;
                                    }
                                } catch (Exception e) {
                                    logger.error("Get error message：{}", e);
                                    sendNotice(false, "负载均衡分配失败：" + e.getMessage(), context);
                                    return;
                                }
                                break;
                            case SecurityGroup:
                                path = SecurityGroup.class.getSimpleName() + "_" + id;
                                try (BocloudACLock lock = lockFactory.getACLock(path)) {
                                    Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                                    SecurityGroup securityGroup = securityGroupRepository.query(id);
                                    Assert.notNull(securityGroup, "安全组数据不存在");
                                    vendor = cloudVendorRepository.query(securityGroup.getVendorId());
                                    Assert.notNull(vendor, "云平台不存在");
                                    CloudProvider segCloudProvider = CloudProvider.valueOf(vendor.getType());
                                    if (CloudProvider.OPENSTACK == segCloudProvider ||
                                            CloudProvider.HCSO == segCloudProvider || CloudProvider.EASYSTACK == segCloudProvider) {
                                        OSTenant osTenant = osTenantRepository.getByTenantId(tenantId, vendor.getId());
                                        if (null == osTenant || !osTenant.getTenantUuid()
                                                .equalsIgnoreCase(securityGroup.getTenantUuid())) {
                                            sendNotice(false, "安全组【" + securityGroup.getName() + "】不允许分配给该租户，所属项目不同",
                                                    context);
                                            return;
                                        }
                                    }
                                    if (0 != securityGroup.getTenantId()
                                            && !tenantIds.contains(securityGroup.getTenantId())) {
                                        securityGroup.setTenantId(0L);
                                    }
                                    securityGroup.setTenantIds(conventor(tenantIds));
                                    securityGroupRepository.update(securityGroup);
                                } catch (Exception e) {
                                    logger.error("Get error message：{}", e);
                                    sendNotice(false, "安全组分配失败：" + e.getMessage(), context);
                                    return;
                                }
                                break;
                            case Snapshot:
                                path = Snapshot.class.getSimpleName() + "_" + id;
                                try (BocloudACLock lock = lockFactory.getACLock(path)) {
                                    Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                                    Snapshot snapshot = snapshotRepository.query(id);
                                    Assert.notNull(snapshot, "快照数据不存在");
                                    vendor = cloudVendorRepository.query(snapshot.getVendorId());
                                    Assert.notNull(vendor, "云平台不存在");

                                    quotas.add(new ResourceQuota("meta.snapshot", 1L));
                                    result = cosInternalService.updateQuotas(quotas, Action.Order, tenantId);
                                    Assert.isTrue(result.isSuccess(), result.getMessage());
                                    if (result.isFailed()) {
                                        sendNotice(false, "快照分配失败：" + result.getMessage(), context);
                                        return;
                                    }
                                    snapshot.setTenantId(tenantId);
                                    snapshot.setExpiredTime(DateTools.stringToDateTime("2099-12-31 00:00:00"));
                                    snapshot.setCatalog(Catalog.User);
                                    snapshot.setMenderId(userId);
                                    snapshot.setOwnerId(userId);
                                    snapshot.setProjectId(projectId);
                                    snapshot.setBusinessId(finalBusinessId);
                                    snapshotRepository.update(snapshot);
                                } catch (Exception e) {
                                    logger.error("Get error message：{}", e);
                                    sendNotice(false, "快照分配失败：" + e.getMessage(), context);
                                    return;
                                }
                                break;
                            default:
                                sendNotice(false, "暂不支持", context);
                                return;
                        }
                        // 处理成功订单
                        resourceOrderService.processOrderStatus(orders, ChargeCommon.ResourceStatus.ready);
                        // 处理订单明细
                        resourceOrderService.processOrderItemStatus(items, OrderItemStatus.OpenedSuccess);
                    }
                    sendNotice(true, "资源分配成功", context);
                } catch (Exception e) {
                    logger.info("资源分配失败租户ID：【{}】,用户ID：【{}】,项目ID【{}】,业务ID：【{}】",tenantId, userId, projectId, finalBusinessId);
                    logger.error("资源分配失败", e);
                    sendNotice(false, "资源分配失败： " + e.getMessage(), context);
                }
            }
        }).start();
        return new BocloudResult(true, "任务已下发，正在执行......");
    }

    public void sendNotice(Boolean result, String content, RequestContext context) {
        resourceEventPublisher.send(new OperateResult(result, content, "", MapTools.simpleMap(Common.VENDORID, 0),
                OperateResult.OperateCategory.ResourceEvent, context));
    }

    public String conventor(List<Long> dataList) {
        String dataString = "";
        try {
            if (!ListTool.isEmpty(dataList)) {
                StringBuilder builder = new StringBuilder();
                dataList.forEach(dataId -> builder.append(dataId).append(","));
                String dataIdsString = builder.toString();
                if (dataIdsString.length() > 0) {
                    dataString = dataIdsString.substring(0, dataIdsString.length() - 1);
                }
            }
        } catch (Exception e) {
            logger.error("数据集合转换异常：" + e);
        }
        return dataString;
    }

    private BocloudResult assignLoadBalance(CloudVendor vendor, Long userId, Long tenantId, Long projectId,
                                            LoadBalancer loadBalancer, List<OrderItem> items, Long orderId, String slbServiceCode, Long businessId) {
        // 下单
        BocloudResult<OrderItem> itemResult = resourceOrderService.createLoadBalancerItem(orderId, slbServiceCode,
                loadBalancer, vendor);
        if (itemResult.isFailed()) {
            return new BocloudResult(false, itemResult.getMessage());
        }
        OrderItem item = itemResult.getData();
        items.add(item);

        loadBalancer.setExpiredTime(DateTools.stringToDateTime("2099-12-31 00:00:00"));
        loadBalancer.setCatalog(Catalog.User);
        loadBalancer.setTenantId(tenantId);
        loadBalancer.setMenderId(userId);
        loadBalancer.setOwnerId(userId);
        loadBalancer.setProjectId(projectId);
        loadBalancer.setUuid(item.getSn());
        loadBalancer.setBusinessId(businessId);
        loadBalancerRepository.update(loadBalancer);
        return new BocloudResult(true, "负载均衡分配成功");
    }

    private void recycleElasticIp(ElasticIp elasticIp, RequestContext context, Boolean isNotice) throws Exception {
        if (null != elasticIp) {
            String orderItemSn = elasticIp.getUuid();
            elasticIp.setUuid(null);
            elasticIp.setProjectId(0L);
            elasticIp.setTenantId(0L);
            elasticIp.setMenderId(0L);
            elasticIp.setOwnerId(0L);
            elasticIp.setExpiredTime(null);
            elasticIp.setGmtModify(new Date());
            elasticIpRepository.update(elasticIp);
            objectRelationRepository.deleteByRid(elasticIp.getId(), ResourceCategory.FloatingIp.name());

            if (isNotice) {
                OrderMessage orderMessage = new OrderMessage(orderItemSn, OrderMessage.Operation.Cancelation,
                        OrderItemStatus.UnsubscribeSuccess, null, "资源回收成功", null, null, new ArrayList<>(),
                        ResourceCategory.FloatingIp.name(), context);
                orderMessage.setCategory(ResourceCategory.FloatingIp.name());
                amqpTemplate.convertAndSend("resource.result.queue", orderMessage);
            }
        }

    }

    private BocloudResult assignElasticIp(CloudVendor vendor, Long userId, Long tenantId, Long projectId,
                                          ElasticIp elasticIp, List<OrderItem> items, Long orderId, String eipServiceCode, Long businessId) {
        // 下单
        BocloudResult<OrderItem> itemResult = resourceOrderService.createElasticIpItem(orderId, eipServiceCode,
                elasticIp, vendor);
        if (itemResult.isFailed()) {
            return new BocloudResult(false, itemResult.getMessage());
        }
        OrderItem item = itemResult.getData();
        items.add(item);

        elasticIp.setExpiredTime(DateTools.stringToDateTime("2099-12-31 00:00:00"));
        elasticIp.setCatalog(Catalog.User);
        elasticIp.setTenantId(tenantId);
        elasticIp.setMenderId(userId);
        elasticIp.setOwnerId(userId);
        elasticIp.setProjectId(projectId);
        elasticIp.setUuid(item.getSn());
        elasticIp.setBusinessId(businessId);
        elasticIpRepository.update(elasticIp);
        return new BocloudResult(true, "浮动IP分配成功");
    }

    private void recycleVpc(Vpc vpc, RequestContext context) {
        if (null != vpc) {
            String orderItemSn = vpc.getUuid();
            vpc.setExpiredTime(null);
            vpc.setCatalog(Catalog.Manager);
            vpc.setTenantId(0L);
            vpc.setMenderId(0L);
            vpc.setOwnerId(0L);
            vpc.setProjectId(0L);
            vpc.setUuid(null);
            vpc.setPoolGroupId(null);
            vpc.setAssgined(false);
            vpcRepository.update(vpc);
            OrderMessage orderMessage = new OrderMessage(orderItemSn, OrderMessage.Operation.Cancelation,
                    OrderItemStatus.UnsubscribeSuccess, null, "资源回收成功", null, null, new ArrayList<>(),
                    ResourceCategory.Vpc.name(), context);
            orderMessage.setCategory(ResourceCategory.Vpc.name());
            amqpTemplate.convertAndSend("resource.result.queue", orderMessage);
        }
    }

    private BocloudResult assignVpc(CloudVendor vendor, Long userId, Long tenantId, Long projectId, Vpc vpc,
                                    List<OrderItem> items, Long orderId, String serviceCode, Long businessId) {
        // 下单
        BocloudResult<OrderItem> createVpcItem = resourceOrderService.createVpcItem(orderId, serviceCode, vpc, vendor);

        if (createVpcItem.isFailed()) {
            return new BocloudResult(false, createVpcItem.getMessage());
        }
        OrderItem item = createVpcItem.getData();
        items.add(item);
        vpc.setExpiredTime(DateTools.stringToDateTime("2099-12-31 00:00:00"));
        vpc.setCatalog(Catalog.User);
        vpc.setTenantId(tenantId);
        vpc.setMenderId(userId);
        vpc.setOwnerId(userId);
        vpc.setProjectId(projectId);
        vpc.setUuid(item.getSn());
        vpc.setAssgined(true);
        vpc.setBusinessId(businessId);

        String regionId = null;
        CloudProvider cloudProvider = CloudProvider.valueOf(vendor.getType());
        switch (cloudProvider) {
            case ALIYUN:
            case HUAWEI:
            case HCSO:
            case TENCENT:
            case AWS:
            case TCE:
            case QCLOUD:
                regionId = vpc.getRegionId();
                break;
            default:
                break;
        }
        // 获取资源池ID
        BocloudResult poolGroupResult = getPoolGroupId(vendor.getId(), tenantId, regionId);
        if (poolGroupResult.isSuccess()) {
            vpc.setPoolGroupId(Long.parseLong(poolGroupResult.getData().toString()));
        }
        vpcRepository.update(vpc);
        return new BocloudResult(true, "VPC分配成功");

    }

    /**
     * 回滚
     *
     * @param orders
     * @param items
     * @param quotas
     */
    private void callback(List<ServiceOrder> orders, List<OrderItem> items, Long tenantId, List<ResourceQuota> quotas) {
        // 回滚配额
        cosInternalService.updateQuotas(quotas, Action.Callback, tenantId);
        quotas.clear();
        // 处理订单
        resourceOrderService.processOrderStatus(orders, ChargeCommon.ResourceStatus.failed);
        orders.clear();
        // 处理订单明细
        resourceOrderService.processOrderItemStatus(items, OrderItemStatus.OpenedFailure);
        items.clear();
    }

    /**
     * 云硬盘服务类型
     *
     * @param vendor
     * @return
     */
    private String getVolumeServiceCode(CloudVendor vendor) {
        String serviceCode = vendor.getType().toLowerCase() + ".standard.volume";
        switch (CloudProvider.valueOf(vendor.getType())) {
            case OPENSTACK:
            case EASYSTACK:
            case ALIYUN:
                break;
            case VMWARE:
                serviceCode = "vmware.storage.disk";
                break;
            case SANGFOR:
                serviceCode = "sangfor.storage.disk";
                break;
            default:
                return serviceCode;
        }
        return serviceCode;
    }

    private String getSlbServiceCode(CloudVendor vendor) {
        String slbServiceCode = "network." + vendor.getType().toLowerCase() + ".slb";
        return slbServiceCode;
    }

    private String getVpcServiceCode(CloudVendor vendor) {
        String vpcServiceCode = vendor.getType().toLowerCase() + ".standard.vpc";
        return vpcServiceCode;
    }

    private String getEipServiceCode(CloudVendor vendor) {
        String eipServiceCode = "network." + vendor.getType().toLowerCase() + ".eip";
        if (CloudProvider.OPENSTACK.name().equalsIgnoreCase(vendor.getType()) || CloudProvider.EASYSTACK.name().equalsIgnoreCase(vendor.getType())) {
            eipServiceCode = CloudProvider.OPENSTACK.name().toLowerCase() + ".standard.eip";
        }
        return eipServiceCode;
    }

    private String getVmServiceCode(CloudVendor vendor) {
        String vmServiceCode = vendor.getType().toLowerCase() + ".standard.server";
        return vmServiceCode;
    }

    @Override
    public BocloudResult reclaim(ResourceAssignParam vmAssignParam, ResourceCategory category, RequestContext context) {
        // 资源ID
        List<Long> serverIds = vmAssignParam.getIds();
        if (ListTool.isEmpty(serverIds)) {
            return new BocloudResult<>(false, "无资源可回收");
        }
        try {
            for (Long id : serverIds) {
                String path = null;
                List<Volume> volumes = Lists.newArrayList();
                List<Snapshot> snaps = Lists.newArrayList();
                List<ResourceQuota> quotas = new ArrayList<>();
                switch (category) {
                    case Computer:
                        path = CloudServer.class.getSimpleName() + "_" + id;
                        try (BocloudACLock lock = lockFactory.getACLock(path)) {
                            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                            CloudServer server = cloudServerRepository.query(id);
                            Assert.notNull(server, "云主机不存在");
                            CloudVendor vendor = cloudVendorRepository.query(server.getVendorId());
                            Assert.notNull(vendor, "云平台不存在");

                            Integer cpu = server.getCpu();
                            BigDecimal memory = server.getMemory();
                            Integer disk = 0;
                            Integer eip = 0;
                            FloatingIp floatingIp = null;
                            ElasticIp elasticIp = null;

                            String serverServiceCode = getVmServiceCode(vendor);
                            String eipServiceCode = getEipServiceCode(vendor);
                            String volumeServiceCode = getVolumeServiceCode(vendor);

                            // 根据平台获取浮动IP
                            if (CloudProvider.ALIYUN.name().equals(server.getVendorType())) {
                                List<ElasticIp> elasticIps = elasticIpRepository.listByIid(server.getInstanceId(),
                                        server.getVendorId());
                                if (!ListTool.isEmpty(elasticIps)) {
                                    elasticIp = elasticIps.get(0);
                                    eip = 1;
                                }
                            } else if (CloudProvider.HUAWEI.name().equals(server.getVendorType())
                                    || CloudProvider.HCSO.name().equals(server.getVendorType())) {
                                elasticIp = elasticIpRepository.queryByAllocationId(server.getInstanceId());
                                if (null != elasticIp) {
                                    eip = 1;
                                }
                            } else if (CloudProvider.TENCENT.name().equals(server.getVendorType())
                                    || CloudProvider.QCLOUD.name().equals(server.getVendorType())) {
                                floatingIp = floatingIpRepository.listByInstanceId(server.getInstanceId(),
                                        server.getVendorId());
                                if (null != floatingIp) {
                                    eip = 1;
                                }
                            } else {
                                floatingIp = floatingIpRepository.listByServerId(server.getInstanceId());
                                if (null != floatingIp) {
                                    eip = 1;
                                }
                            }
                            volumes = volumeRepository.listByServerId(server.getId());
                            List<Snapshot> snapshots = new ArrayList<>();
                            if (!ListTool.isEmpty(volumes)) {
                                Long volumeCount = 0L;
                                for (Volume volume : volumes) {
                                    volumeCount += 1;
                                    //
                                    Integer size = volume.getSize();
                                    if (null != size) {
                                        disk = disk + size;
                                    }
                                    //磁盘的快照
                                    Pager pager = new Pager(1, Integer.MAX_VALUE, new ArrayList<>(), new HashMap<>());
                                    List<Snapshot> volumeSnapshots = snapshotRepository.listByVolumeId(volume.getId(), pager);
                                    if(!ListTool.isEmpty(volumeSnapshots)) {
                                        snapshots.addAll(volumeSnapshots);
                                    }
                                }
                                if (!CloudProvider.VMWARE.name().equals(server.getVendorType())) {
                                    quotas.add(new ResourceQuota(volumeServiceCode, volumeCount));
                                }
                            }
                            // vc获取快照信息
                            if (CloudProvider.VMWARE.name().equals(server.getVendorType())) {
                                List<Snapshot> vcSnaps = snapshotRepository.listByVMid(server.getId());
                                if(!ListTool.isEmpty(vcSnaps)) {
                                    snapshots.addAll(vcSnaps);
                                }
                            }
                            quotas.add(new ResourceQuota("meta.cpu", Long.valueOf(cpu)));
                            quotas.add(new ResourceQuota("meta.mem", memory.longValue()));
                            quotas.add(new ResourceQuota("meta.disk", Long.valueOf(disk)));
                            quotas.add(new ResourceQuota(serverServiceCode, 1L));
                            if (eip != 0) {
                                quotas.add(new ResourceQuota(eipServiceCode, Long.valueOf(eip)));
                            }
                            // 回收云主机
                            recycleServer(server, vendor, context, true);
                            recycleVolume(volumes, context, true);
                            recycleFloatingIp(floatingIp, context, true);
                            recycleElasticIp(elasticIp, context, true);
                            recycleSnapshot(snapshots, context, true);
                        } catch (Exception e) {
                            logger.error("Get error message：", e);
                            return new BocloudResult(false, e.getMessage());
                        }
                        break;
                    case Storage:
                        path = Volume.class.getSimpleName() + "_" + id;
                        try (BocloudACLock lock = lockFactory.getACLock(path)) {
                            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                            Volume volume = volumeRepository.query(id);
                            Assert.notNull(volume, "云硬盘不存在");
                            volumes.add(volume);
                            recycleVolume(volumes, context, true);
                            Pager pager = new Pager(1, Integer.MAX_VALUE, new ArrayList<>(), new HashMap<>());
                            List<Snapshot> snapshots = snapshotRepository.listByVolumeId(volume.getId(), pager);
                            recycleSnapshot(snapshots, context, true);
                        } catch (Exception e) {
                            logger.error("Get error message：", e);
                            return new BocloudResult(false, e.getMessage());
                        }
                        break;
                    case Vpc:
                        path = Vpc.class.getSimpleName() + "_" + id;
                        try (BocloudACLock lock = lockFactory.getACLock(path)) {
                            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                            Vpc vpc = vpcRepository.query(id);
                            Assert.notNull(vpc, "VPC不存在");
                            Long vendorId = vpc.getVendorId();
                            Long tenantId = vpc.getTenantId();
                            CloudVendor vpcCloudVendor = cloudVendorRepository.query(vendorId);
                            Assert.notNull(vpcCloudVendor, "云平台不存在");
                            String vpcServiceCode = getVpcServiceCode(vpcCloudVendor);
                            quotas.add(new ResourceQuota(vpcServiceCode, Long.valueOf(1)));
                            recycleVpc(vpc, context);
                            // 如果当前VPC对应的网络为op 且网络类型为非共享 则删除该VPC
                            if (CloudProvider.OPENSTACK.name().equals(vpcCloudVendor.getType()) || CloudProvider.EASYSTACK.name().equals(vpcCloudVendor.getType())) {
                                Long networkId = vpc.getNetworkId();
                                Network network = networkRepository.query(networkId);
                                vpcRepository.delete(id);
                                tenantNetworkRepository.delete(networkId, tenantId, vendorId);
                                network.setTenantId(0L);
                                networkRepository.update(network);
                            }
                            // 如果当前VPC属于阿里云 回收时自动回收vpc下的安全组
                            if (CloudProvider.ALIYUN.name().equals(vpcCloudVendor.getType())) {
                                List<SecurityGroup> securityGroups = securityGroupRepository.listByVpcId(vpc.getId(), null);
                                if (!ListTool.isEmpty(securityGroups)) {
                                    List<Long> securityGroupIds = securityGroups.stream().map(SecurityGroup::getId)
                                            .collect(Collectors.toList());
                                    ResourceAssignParam networkAssignParam = new ResourceAssignParam();
                                    networkAssignParam.setIds(securityGroupIds);
                                    networkAssignParam.setResourceCategory(ResourceCategory.SecurityGroup);
                                    this.reclaim(networkAssignParam, ResourceCategory.SecurityGroup, context);
                                }
                            }
                        } catch (Exception e) {
                            logger.error("Get error message：", e);
                            return new BocloudResult(false, e.getMessage());
                        }
                        break;
                    case Network:
                        path = Network.class.getSimpleName() + "_" + id;
                        try (BocloudACLock lock = lockFactory.getACLock(path)) {
                            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                            Network network = networkRepository.query(id);
                            Assert.notNull(network, "网络不存在");
                            CloudVendor vpcCloudVendor = cloudVendorRepository.query(network.getVendorId());
                            Assert.notNull(vpcCloudVendor, "云平台不存在");
                            List<Vpc> vpcs = vpcRepository.listByNetworkId(network.getId());
                            if (ListTool.isEmpty(vpcs)) {
                                tenantNetworkRepository.deleteByNetworkId(network.getId());
                                network.setTenantId(0L);
                                networkRepository.update(network);
                                return new BocloudResult(true, "回收成功！");
                            }
                            List<Long> vpcIds = new ArrayList<Long>();
                            if (network.getShared()) {
                                List<Long> tenantIds = vmAssignParam.getTenantIds();
                                if (ListTool.isEmpty(tenantIds)) {
                                    return new BocloudResult<>(true, "资源回收成功");
                                }
                                List<Vpc> tenantVpcs = new ArrayList<Vpc>();
                                for (Vpc vpc : vpcs) {
                                    if (tenantIds.contains(vpc.getTenantId())) {
                                        tenantVpcs.add(vpc);
                                    }
                                }
                                vpcIds = tenantVpcs.stream().map(Vpc::getId).collect(Collectors.toList());
                            } else {
                                vpcIds = vpcs.stream().map(Vpc::getId).collect(Collectors.toList());
                            }
                            if (!ListTool.isEmpty(vpcIds)) {
                                ResourceAssignParam networkAssignParam = new ResourceAssignParam();
                                networkAssignParam.setIds(vpcIds);
                                networkAssignParam.setResourceCategory(ResourceCategory.Vpc);
                                this.reclaim(networkAssignParam, ResourceCategory.Vpc, context);
                            }
                        } catch (Exception e) {
                            logger.error("Get error message：", e);
                            return new BocloudResult(false, e.getMessage());
                        }
                        break;
                    case FloatingIp:
                        String vendorType = vmAssignParam.getVendorType();
                        CloudProvider cloudProvider = CloudProvider.valueOf(vendorType);
                        FloatingIp floatingIp = null;
                        ElasticIp elasticIp = null;
                        if (CloudProvider.ALIYUN == cloudProvider || CloudProvider.HUAWEI == cloudProvider
                                || CloudProvider.AWS == cloudProvider) {
                            elasticIp = elasticIpRepository.query(id);
                        } else {
                            floatingIp = floatingIpRepository.query(id);
                        }
                        recycleElasticIp(elasticIp, context, true);
                        recycleFloatingIp(floatingIp, context, true);
                        break;
                    case LoadBalance:
                        path = LoadBalancer.class.getSimpleName() + "_" + id;
                        try (BocloudACLock lock = lockFactory.getACLock(path)) {
                            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                            LoadBalancer loadBalancer = loadBalancerRepository.query(id);
                            Assert.notNull(loadBalancer, "负载均衡不存在");
                            CloudVendor slbCloudVendor = cloudVendorRepository.query(loadBalancer.getVendorId());
                            Assert.notNull(slbCloudVendor, "云平台不存在");
                            String slbServiceCode = getSlbServiceCode(slbCloudVendor);
                            quotas.add(new ResourceQuota(slbServiceCode, 1L));
                            recycleLoadBalancer(loadBalancer, context);
                        } catch (Exception e) {
                            logger.error("Get error message：", e);
                            return new BocloudResult(false, e.getMessage());
                        }
                        break;
                    case Snapshot:
                        path = LoadBalancer.class.getSimpleName() + "_" + id;
                        try (BocloudACLock lock = lockFactory.getACLock(path)) {
                            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                            Snapshot snapshot = snapshotRepository.query(id);
                            Assert.notNull(snapshot, "快照数据不存在");
                            Long tenantId = snapshot.getTenantId();
                            CloudVendor snapCloudVendor = cloudVendorRepository.query(snapshot.getVendorId());
                            Assert.notNull(snapCloudVendor, "云平台不存在");
                            quotas.add(new ResourceQuota("meta.snapshot", 1L));
                            snapshot.setTenantId(0L);
                            snapshot.setProjectId(0L);
                            snapshot.setCatalog(Catalog.Manager);
                            snapshot.setMenderId(0L);
                            snapshot.setOwnerId(0L);
                            snapshotRepository.update(snapshot);
                            BocloudResult snapshotUpdateQuotas = cosInternalService.updateQuotas(quotas, Action.Callback,
                                    tenantId);
                            if (snapshotUpdateQuotas.isFailed()) {
                                return snapshotUpdateQuotas;
                            }
                        } catch (Exception e) {
                            logger.error("Get error message：", e);
                            return new BocloudResult(false, e.getMessage());
                        }
                        break;
                    default:
                        break;
                }
            }
        } catch (Exception e) {
            logger.error("Get error message：", e);
            return new BocloudResult(false, "资源回收失败");
        }
        logger.info("资源{}回收成功", JSON.toJSONString(serverIds));
        return new BocloudResult(true, "资源回收成功");
    }

    @Override
    public BocloudResult<GridBean<CloudServer>> resourceList(Pager pager, RequestContext context) {
        GridBean<CloudServer> gridBean;
        try {
            List<Param> params = Optional.ofNullable(pager.getParams()).orElse(new ArrayList<>());

            Map<String, String> sorter = Optional.ofNullable(pager.getSorter()).orElse(Maps.newLinkedHashMap());
            if (sorter.getClass().equals(HashMap.class)) {
                sorter = new LinkedHashMap<>(sorter);
                pager.setSorter(sorter);
            }
            sorter.put("managerIp", Common.ZERO);
            sorter.put("id", Common.ZERO);

            Integer page = Optional.ofNullable(pager.getPage()).orElse(1);
            Integer rows = Optional.ofNullable(pager.getRows()).orElse(10);
            String time = null;
            for (Param param : params) {
                Map<String, Object> paramMap = param.getParam();
                if (paramMap.containsKey("time")) {
                    time = paramMap.get("time").toString();
                    paramMap.remove("time");
                }
            }

            boolean isDate = DateUtils.isDate(time, TIME_FORMAT);
            if (!isDate) {
                return new BocloudResult<>(false, "时间参数"+time+"不合法");
            }
            Date date = DateUtils.stringToDate(time, TIME_FORMAT);

            int total = this.cloudServerRepository.countResourceList(params, date);
            List<CloudServer> list = this.cloudServerRepository.listResource(page, rows, params, sorter, date);
            gridBean = new GridBean<>(page, rows, total, list);

            Map<String, String> statusMap = new HashMap<>();
            statusMap.put("RUNNING", "运行中");
            statusMap.put("STOPPED", "已关机");
            statusMap.put("BUILDING", "创建中");
            statusMap.put("STARTING", "启动中");
            statusMap.put("STOPPING", "关机中");
            statusMap.put("ERROR", "错误");
            statusMap.put("UNKNOWN", "未知");
            String status, statusName;
            for (CloudServer vm : list) {
                status = vm.getStatus();
                if (StringUtils.isEmpty(status)) {
                    status = "UNKNOWN";
                }
                statusName = statusMap.get(status);
                if (StringUtils.isEmpty(statusName)) {
                    statusName = "UNKNOWN";
                }
                vm.setStatusName(statusName);
            }

            return new BocloudResult(true, gridBean, "查询資源分配列表成功");
        } catch (Exception e) {
            logger.error("Query vm list fail", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult<GridBean<CloudServer>> serverList(Pager pager, RequestContext context) {
        GridBean<CloudServer> gridBean;
        try {
            List<Param> params = Optional.ofNullable(pager.getParams()).orElse(new ArrayList<>());
            Boolean simple = Optional.ofNullable(pager.getSimple()).orElse(false);

            Map<String, String> sorter = Optional.ofNullable(pager.getSorter()).orElse(Maps.newLinkedHashMap());
            if (sorter.getClass().equals(HashMap.class)) {
                sorter = new LinkedHashMap<>(sorter);
                pager.setSorter(sorter);
            }
            sorter.put("expiredTime", Common.ONE);

            Integer page = Optional.ofNullable(pager.getPage()).orElse(1);
            Integer rows = Optional.ofNullable(pager.getRows()).orElse(10);
            String expiredTime = null;
            for (Param param : params) {
                Map<String, Object> paramMap = param.getParam();
                if (paramMap.containsKey("expiredTime")) {
                    expiredTime = paramMap.get("expiredTime").toString();
                    paramMap.remove("expiredTime");
                }
            }
            int total = 0;
            List<CloudServer> list = Lists.newArrayList();
            if (simple) {
                rows = Integer.MAX_VALUE;
            }
            total = this.cloudServerRepository.countByTime(params, expiredTime);
            list = this.cloudServerRepository.listByTime(page, rows, params,
                    sorter, expiredTime);
            // 处理申请人名称
            list = list.stream().map(o -> {
                String applicantName = "";
                BocloudResult<User> detail = smsUserService.detail(o.getCreatorId());
                if (detail.isSuccess()) {
                    User data = detail.getData();
                    applicantName = data.getName();
                }
                o.setOwnerName(applicantName);
                return o;
            }).collect(Collectors.toList());
            gridBean = new GridBean<>(page, rows, total, list);
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("Query vm list fail", e);
            return new BocloudResult<>(false, "查询失败");
        }
    }

    @Override
    public BocloudResult<Map<String, Object>> downLoadResourceList(String time, RequestContext context) {
        SXSSFWorkbook workbook = new SXSSFWorkbook();
        try {
            SXSSFSheet sheet = workbook.createSheet("sheet");
            sheet.setRandomAccessWindowSize(-1);
            // 样式一，标题数据蓝色填充
            CellStyle style = workbook.createCellStyle();
            style.setFillForegroundColor(IndexedColors.ROYAL_BLUE.getIndex());
            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            style.setBorderBottom(BorderStyle.THIN); // 下边框
            style.setBorderLeft(BorderStyle.THIN);// 左边框
            style.setBorderTop(BorderStyle.THIN);// 上边框
            style.setBorderRight(BorderStyle.THIN);// 右边框
            style.setAlignment(HorizontalAlignment.CENTER);
            // 样式二，内容样式
            CellStyle cellStyle = workbook.createCellStyle();
            cellStyle.setBorderTop(BorderStyle.THIN);// 上边框
            cellStyle.setBorderBottom(BorderStyle.THIN); // 下边框
            cellStyle.setBorderLeft(BorderStyle.THIN);// 左边框
            cellStyle.setBorderRight(BorderStyle.THIN);// 右边框
            cellStyle.setAlignment(HorizontalAlignment.CENTER);// 水平对齐方式
            cellStyle.setVerticalAlignment(VerticalAlignment.TOP);// 垂直对齐方式
            // 标题写入
            createReport(sheet, style, "CloudResourceStatus");
            // 读写数据
            excelExporter(sheet, cellStyle, context, null, time, "CloudResourceStatus");
            String fileName = "资源分配清单";
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            workbook.write(byteArrayOutputStream);
            byte[] ba = byteArrayOutputStream.toByteArray();
            Map<String, Object> resultMap = Maps.newHashMap();
            resultMap.put("fileName", fileName + System.currentTimeMillis() + ".xlsx");
            resultMap.put("data", Base64.getEncoder().encodeToString(ba));
            return new BocloudResult<>(true, resultMap, "下载成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e.getMessage(), e);
            return new BocloudResult<>(false, e.getMessage());
        } finally {
            if (null != workbook) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    logger.error("error message：", e);
                }
            }
        }
    }

    @Override
    public BocloudResult<Map<String, Object>> downLoadServerList(String name, String time, RequestContext context) {
        SXSSFWorkbook workbook = new SXSSFWorkbook();
        try {
            SXSSFSheet sheet = workbook.createSheet("sheet");
            sheet.setRandomAccessWindowSize(-1);
            // 样式一，标题数据蓝色填充
            CellStyle style = workbook.createCellStyle();
            style.setFillForegroundColor(IndexedColors.ROYAL_BLUE.getIndex());
            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
            style.setBorderBottom(BorderStyle.THIN); // 下边框
            style.setBorderLeft(BorderStyle.THIN);// 左边框
            style.setBorderTop(BorderStyle.THIN);// 上边框
            style.setBorderRight(BorderStyle.THIN);// 右边框
            style.setAlignment(HorizontalAlignment.CENTER);
            // 样式二，内容样式
            CellStyle cellStyle = workbook.createCellStyle();
            cellStyle.setBorderTop(BorderStyle.THIN);// 上边框
            cellStyle.setBorderBottom(BorderStyle.THIN); // 下边框
            cellStyle.setBorderLeft(BorderStyle.THIN);// 左边框
            cellStyle.setBorderRight(BorderStyle.THIN);// 右边框
            cellStyle.setAlignment(HorizontalAlignment.CENTER);// 水平对齐方式
            cellStyle.setVerticalAlignment(VerticalAlignment.TOP);// 垂直对齐方式
            // 标题写入
            createReport(sheet, style, "VirtualMachineList");
            // 读写数据
            excelExporter(sheet, cellStyle, context, name, time, "VirtualMachineList");
            String fileName = "到期云主机清单";
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            workbook.write(byteArrayOutputStream);
            byte[] ba = byteArrayOutputStream.toByteArray();
            Map<String, Object> resultMap = Maps.newHashMap();
            resultMap.put("fileName", fileName + System.currentTimeMillis() + ".xlsx");
            resultMap.put("data", Base64.getEncoder().encodeToString(ba));
            return new BocloudResult<>(true, resultMap, "下载成功");
        } catch (Exception e) {
            logger.error("Get error message：{}", e.getMessage(), e);
            return new BocloudResult<>(false, e.getMessage());
        } finally {
            if (null != workbook) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    logger.error("error message：", e);
                }
            }
        }
    }

    private void excelExporter(SXSSFSheet sheet, CellStyle cellStyle, RequestContext context, String name, String time, String type) {

        SimpleDateFormat sdf = new SimpleDateFormat(TIME_FORMAT);

        if ("CloudResourceStatus".equalsIgnoreCase(type)) {
            // 设置一页数据
            Pager pager = new Pager();
            pager.setPage(1);
            pager.setRows(Integer.MAX_VALUE);
            List<Param> params = new ArrayList<>();
            if (!StringUtils.isEmpty(time)) {
                Param timeParam = new Param();
                timeParam.setParam(MapTools.simpleMap("time", time));
                timeParam.setSign(Sign.EQ);
                params.add(timeParam);
            }
            pager.setParams(params);

            BocloudResult<GridBean<CloudServer>> bocloudResult = resourceList(pager, context);
            if(bocloudResult.isFailed()) {
                throw new RuntimeException("查询虚拟机信息出错，" + bocloudResult.getMessage());
            }
            Integer row = 2;
            GridBean<CloudServer> data = bocloudResult.getData();
            for (CloudServer vm : data.getRows()) {
                // 云平台名称、项目名称、虚拟机名称、操作系统、IP、状态、CPU(核数)、内存(GB)、磁盘(GB)、到期时间、所属用户、创建时间。
                //vendorName,projectName,name,osName,managerIp,statusName,cpu,memory,disk,expiredTime,ownerName,gmtCreate
                SXSSFRow sheetRow = sheet.createRow(row);
                sheetRow.createCell(0).setCellValue(vm.getVendorName());
                sheet.getRow(row).getCell(0).setCellStyle(cellStyle);
                sheetRow.createCell(1).setCellValue(vm.getProjectName());
                sheet.getRow(row).getCell(1).setCellStyle(cellStyle);
                sheetRow.createCell(2).setCellValue(vm.getName());
                sheet.getRow(row).getCell(2).setCellStyle(cellStyle);
                sheetRow.createCell(3).setCellValue(vm.getOsName() == null ? "" : vm.getOsName());
                sheet.getRow(row).getCell(3).setCellStyle(cellStyle);
                sheetRow.createCell(4).setCellValue(vm.getManagerIp());
                sheet.getRow(row).getCell(4).setCellStyle(cellStyle);
                sheetRow.createCell(5).setCellValue(vm.getStatusName());
                sheet.getRow(row).getCell(5).setCellStyle(cellStyle);
                sheetRow.createCell(6).setCellValue(vm.getCpu());
                sheet.getRow(row).getCell(6).setCellStyle(cellStyle);
                sheetRow.createCell(7).setCellValue(vm.getMemory() == null ? 0 : vm.getMemory().intValue());
                sheet.getRow(row).getCell(7).setCellStyle(cellStyle);
                sheetRow.createCell(8).setCellValue(vm.getDisk());
                sheet.getRow(row).getCell(8).setCellStyle(cellStyle);
                sheetRow.createCell(9).setCellValue(vm.getExpiredTime() == null ? "" : DateUtils.dateToString(vm.getExpiredTime(), "yyyy-MM-dd HH:mm:ss"));
                sheet.getRow(row).getCell(9).setCellStyle(cellStyle);
                sheetRow.createCell(10).setCellValue(vm.getOwnerName());
                sheet.getRow(row).getCell(10).setCellStyle(cellStyle);
                sheetRow.createCell(11).setCellValue(vm.getGmtCreate() == null ? "" : DateUtils.dateToString(vm.getGmtCreate(), "yyyy-MM-dd HH:mm:ss"));
                sheet.getRow(row).getCell(11).setCellStyle(cellStyle);
                row++;
            }
        } else if ("VirtualMachineList".equalsIgnoreCase(type)) {
            List<CloudServer> cloudServers = new ArrayList<>();
            // 设置一页数据
            Pager pager = new Pager();
            List<Param> params = new ArrayList<>();
            if (!StringUtils.isEmpty(name)) {
                Param nameParam = new Param();
                nameParam.setParam(MapTools.simpleMap("name", name));
                nameParam.setSign(Sign.LK);
                params.add(nameParam);
            }
            if (!StringUtils.isEmpty(time)) {
                Param timeParam = new Param();
                timeParam.setParam(MapTools.simpleMap("expiredTime", time));
                timeParam.setSign(Sign.LET);
                params.add(timeParam);
            }
            pager.setPage(1);
            pager.setRows(Integer.MAX_VALUE);
            pager.setParams(params);
            BocloudResult<GridBean<CloudServer>> gridBeanBocloudResult = serverList(pager, context);
            if (gridBeanBocloudResult.isSuccess()) {
                GridBean<CloudServer> data = gridBeanBocloudResult.getData();
                cloudServers.addAll(data.getRows());
            }

            Integer row = 2;
            for (CloudServer server : cloudServers) {
                SXSSFRow sheetRow = sheet.createRow(row);
                sheetRow.createCell(0).setCellValue(server.getName());
                sheet.getRow(row).getCell(0).setCellStyle(cellStyle);

                String vendorType = server.getVendorType();
                String privateIps = server.getPrivateIps();
                String ipString = ResourceAllocateServiceImpl.getIpString(server, vendorType, privateIps);

                sheetRow.createCell(1).setCellValue(ipString);
                sheet.getRow(row).getCell(1).setCellStyle(cellStyle);
                sheetRow.createCell(2).setCellValue(server.getVendorName());
                sheet.getRow(row).getCell(2).setCellStyle(cellStyle);
                BocloudResult<User> detail = smsUserService.detail(server.getCreatorId());
                String applicantName = "";
                if (detail.isSuccess()) {
                    User data = detail.getData();
                    applicantName = data.getName();
                }
                sheetRow.createCell(3).setCellValue(applicantName);
                sheet.getRow(row).getCell(3).setCellStyle(cellStyle);
                Date expiredTime = server.getExpiredTime();
                sheetRow.createCell(4).setCellValue(expiredTime == null ? "" : sdf.format(expiredTime));
                sheet.getRow(row).getCell(4).setCellStyle(cellStyle);
                row++;
            }

        }
    }

    /**
     * 通用privateIps解析类 针对不同平台的privateIps使用不同的字段解析方式
     *
     * @param server
     * @param vendorType
     * @param privateIps
     * @return
     */
    public static String getIpString(CloudServer server, String vendorType, String privateIps) {

        String ipString = "";
        List<String> ipList = null;
        switch (CloudProvider.valueOf(vendorType)) {
            case TIANYI:
            case AWS:
            case ALIYUN:
                List<String> parseArray = JSON.parseArray(privateIps, String.class);
                ipList = new ArrayList<>();
                if (!ListTool.isEmpty(parseArray)) {
                    for (String ip : parseArray) {
                        ipList.add(ip);
                    }
                }
                ipString = String.join(",", ipList);
                break;
            case VMWARE:
            case HUAWEI:
                if (!StringUtils.isEmpty(privateIps)) {
                    ipList = ShtermService.getVmwareIpList(privateIps);
                    ipString = String.join(",", ipList);
                }
                break;
            case SANGFOR:
                if (!StringUtils.isEmpty(privateIps)) {
                    ipList = ShtermService.getSangforIpList(server, privateIps);
                    ipString = String.join(",", ipList);
                }
                break;
            default:
                break;
        }
        return ipString;
    }

    private void createReport(SXSSFSheet sheet, CellStyle style, String type) {
        // 模板标题处理
        String[] titles = new String[]{};
        if ("CloudResourceStatus".equalsIgnoreCase(type)) {
            // 云平台名称、项目名称、虚拟机名称、操作系统、IP、状态、CPU(核数)、内存(GB)、磁盘(GB)、到期时间、所属用户、创建时间。
            //vendorName,projectName,name,osName,managerIp,statusName,cpu,memory,disk,expiredTime,ownerName,gmtCreate
            titles = new String[]{"云平台名称", "项目名称", "虚拟机名称", "操作系统", "IP", "状态", "CPU(核数)", "内存(GB)", "磁盘(GB)", "到期时间", "所属用户", "创建时间"};
        } else if ("VirtualMachineList".equalsIgnoreCase(type)) {
            titles = new String[]{"虚拟机名称", "IP地址", "所属云平台", "申请人", "过期时间"};
        }


        int number = -1;
        SXSSFRow row = sheet.createRow(0);
        for (String title : titles) {
            number++;
            row.createCell(number).setCellValue(title);
            sheet.getRow(0).getCell(number).setCellStyle(style);
            sheet.setColumnWidth(number, 30 * 256);
            sheet.addMergedRegion(new CellRangeAddress(0, 1, number, number));
        }
    }

    private void recycleLoadBalancer(LoadBalancer loadBalancer, RequestContext context) {
        if (null != loadBalancer) {
            String orderItemSn = loadBalancer.getUuid();
            loadBalancer.setExpiredTime(null);
            loadBalancer.setCatalog(Catalog.Manager);
            loadBalancer.setTenantId(0L);
            loadBalancer.setMenderId(0L);
            loadBalancer.setOwnerId(0L);
            loadBalancer.setProjectId(0L);
            loadBalancer.setUuid(null);
            loadBalancerRepository.update(loadBalancer);

            OrderMessage orderMessage = new OrderMessage(orderItemSn, OrderMessage.Operation.Cancelation,
                    OrderItemStatus.UnsubscribeSuccess, null, "负载均衡退订成功", null, null, new ArrayList<>(),
                    ResourceCategory.LoadBalance.name(), context);
            orderMessage.setCategory(ResourceCategory.LoadBalance.name());
            amqpTemplate.convertAndSend("resource.result.queue", orderMessage);
        }
    }

    /**
     * 分配云主机
     *
     * @param vendor
     * @param server
     * @param userId
     * @param tenantId
     * @param projectId
     * @param items
     * @param orderId
     * @return
     * @throws Exception
     */
    private BocloudResult assignServer(CloudVendor vendor, CloudServer server, Long userId, Long tenantId,
                                       Long projectId, List<OrderItem> items, Long orderId, String serverServiceCode, Long businessId) throws Exception {
        // 下单
        BocloudResult<OrderItem> itemResult = resourceOrderService.createServerItem(orderId, serverServiceCode, server,
                vendor);
        if (itemResult.isFailed()) {
            return new BocloudResult(false, itemResult.getMessage());
        }
        OrderItem item = itemResult.getData();
        items.add(item);

        Date expiredTime = server.getExpiredTime();
        if (null == expiredTime) {
            server.setExpiredTime(DateTools.stringToDateTime("2099-12-31 00:00:00"));
        }
        // 自服务需要用到
        server.setOwnerId(userId);
        server.setBusinessId(businessId);
        server.setMenderId(userId);
        server.setCatalog(Catalog.User);
        server.setTenantId(tenantId);
        server.setRecycle(false);
        server.setProjectId(projectId);
        server.setUuid(item.getSn());
        // 获取资源池ID
        BocloudResult poolGroupResult = getPoolGroupId(vendor.getId(), tenantId, null);
        if (poolGroupResult.isSuccess()) {
            server.setPoolGroupId(Long.parseLong(poolGroupResult.getData().toString()));
        }
        cloudServerRepository.update(server);
        List<String> ips = Lists.newArrayList();
        String vendorType = server.getVendorType();
        switch (CloudProvider.valueOf(vendorType)) {
            case VMWARE:
                if (!StringUtils.isEmpty(server.getPrivateIps())) {
                    List<JSONObject> objects = JSONObject.parseArray(server.getPrivateIps(), JSONObject.class);
                    for (JSONObject jsonObject : objects) {
                        if (StringUtils.isEmpty(jsonObject.getString("address"))) {
                            continue;
                        }
                        ips.add(jsonObject.getString("address"));
                    }
                }
                break;
            default:
                break;
        }
        Resource resource = resourceRepository.query(ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(),
                server.getId());
        if (null == resource) {
            resource = new Resource(ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(), server.getId(),
                    JSONObject.toJSONString(ips), server.getOsCategory(), server.getVendorId());
            resource.preSave(server.getName(), server.getStatus(), 1L, tenantId);
            resource.setInventory(JSONObject.toJSONString(server));
            resourceRepository.save(resource);
        } else {
            resource.setTenantId(tenantId);
            resource.setMenderId(userId);
            resource.setOwnerId(userId);
            resource.setGmtModify(new Date());
            resourceRepository.update(resource);
        }
        return new BocloudResult(true, "分配云主机成功");
    }

    public BocloudResult getPoolGroupId(Long vendorId, Long tenantId, String regionId) {
        try {
            JSONObject object = new JSONObject();
            object.put("condition", "listByVendorId");
            object.put("vendorId", vendorId);
            object.put("tenantId", tenantId);
            object.put("regionId", regionId);
            BocloudResult tenantPoolGroupResult = resourcePoolService.condition(null, object.toJSONString(), null);
            if (tenantPoolGroupResult.isFailed()) {
                return new BocloudResult<>(false, "当前租户未绑定相关平台资源池");
            }
            PoolGroup findGroup = (PoolGroup) tenantPoolGroupResult.getData();
            if (null == findGroup) {
                return new BocloudResult<>(false, "当前租户未绑定相关平台资源池");
            }
            return new BocloudResult<>(true, findGroup.getId(), "查询成功");
        } catch (Exception e) {
            logger.error("查询租户资源池异常: " + e.getMessage());
            return new BocloudResult<>(false, "当前租户未绑定相关平台资源池");
        }
    }

    /**
     * 回收分配给租户的云主机
     *
     * @param server
     * @param vendor
     * @param context
     * @throws Exception
     */
    private void recycleServer(CloudServer server, CloudVendor vendor, RequestContext context, Boolean isNotice)
            throws Exception {
        objectRelationRepository.deleteByRid(server.getId(), ResourceCategory.Computer.name());
        List<String> ips = Lists.newArrayList();
        String vendorType = server.getVendorType();
        switch (CloudProvider.valueOf(vendorType)) {
            case VMWARE:
                if (!StringUtils.isEmpty(server.getPrivateIps())) {
                    List<JSONObject> objects = JSONObject.parseArray(server.getPrivateIps(), JSONObject.class);
                    for (JSONObject jsonObject : objects) {
                        if (StringUtils.isEmpty(jsonObject.getString("address"))) {
                            continue;
                        }
                        ips.add(jsonObject.getString("address"));
                    }
                }
            default:
                break;
        }
        Resource resource = resourceRepository.query(ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(),
                server.getId());
        if (null == resource) {
            resource = new Resource(ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(), server.getId(),
                    JSONObject.toJSONString(ips), server.getOsCategory(), vendor.getId());
            resource.preSave(server.getName(), server.getStatus(),
                    server.getCreatorId() == null ? 1L : server.getCreatorId(), 0L);
            resource.setInventory(JSONObject.toJSONString(server));
            resourceRepository.save(resource);
        } else {
            resource.setTenantId(0L);
            resource.setOwnerId(context.getTarget());
            resource.setMenderId(context.getTarget());
            resource.setGmtModify(new Date());
            resourceRepository.update(resource);
        }
        Boolean recycle = server.getRecycle();
        String orderItemSn = server.getUuid();
        server.setUuid(null);
        server.setExpiredTime(null);
        server.setTenantId(0L);
        server.setOwnerId(0L);
        server.setProjectId(0L);
        server.setBusinessId(0L);
        server.setCatalog(Catalog.Manager);
        server.setMenderId(0L);
        server.setGmtModify(new Date());
        server.setPoolGroupId(null);
        server.setRecycle(false);
        cloudServerRepository.update(server);
        if (isNotice) {
            OrderMessage message = new OrderMessage(orderItemSn, Operation.Cancelation,
                    OrderItemStatus.UnsubscribeSuccess, null, "资源回收成功", null, null, null,
                    ResourceCategory.Computer.name(), context);
            message.setCategory(ResourceCategory.Computer.name());
            amqpTemplate.convertAndSend("resource.result.queue", message);
        }

        if (null != recycle && recycle) {
            cosInternalService.recycle(orderItemSn);
        }
        // 终止订单
        // cosInternalService.updateItemStatus(server.getUuid(),
        // OrderItemStatus.Termination.name());
    }

    /**
     * 分配云硬盘给租户用户
     *
     * @param vendor
     * @param userId
     * @param tenantId
     * @param projectId
     * @param volumes
     * @param items
     * @param orderId
     * @param serviceCode
     * @return
     * @throws Exception
     */
    private BocloudResult assignVolume(CloudVendor vendor, Long userId, Long tenantId, Long projectId,
                                       List<Volume> volumes, List<OrderItem> items, Long orderId, String serviceCode, Long businessId) throws Exception {
        if (ListTool.isEmpty(volumes)) {
            return new BocloudResult<>(true, "云硬盘分配成功");
        }
        for (Volume volume : volumes) {
            // 下单
            BocloudResult<OrderItem> itemResult = resourceOrderService.createVolumeItem(orderId, serviceCode, volume,
                    vendor);
            if (itemResult.isFailed()) {
                return new BocloudResult(false, itemResult.getMessage());
            }
            OrderItem item = itemResult.getData();
            items.add(item);
            volume.setExpiredTime(DateTools.stringToDateTime("2099-12-31 00:00:00"));
            // 自服务需要用到
            volume.setOwnerId(userId);
            volume.setMenderId(userId);
            volume.setCatalog(Catalog.User);
            volume.setTenantId(tenantId);
            volume.setProjectId(projectId);
            volume.setSkuId(item.getSkuId());
            volume.setUuid(item.getSn());
            volume.setBusinessId(businessId);
            volumeRepository.update(volume);
        }

        return new BocloudResult(true, "云硬盘分配成功");
    }

    /**
     * 回收分配给租户的云硬盘
     *
     * @param volumes
     * @param context
     * @throws Exception
     */
    private void recycleVolume(List<Volume> volumes, RequestContext context, Boolean isNotice) throws Exception {
        if (ListTool.isEmpty(volumes)) {
            return;
        }
        OrderMessage volumeOrderMessage = new OrderMessage(null, Operation.Cancelation,
                OrderItemStatus.UnsubscribeSuccess, null, "资源回收成功", null, null, new ArrayList<>(),
                ResourceCategory.Storage.name(), context);
        volumeOrderMessage.setCategory(ResourceCategory.Storage.name());
        for (Volume volume : volumes) {
            String orderItemSn = volume.getUuid();
            volume.setTenantId(0L);
            volume.setProjectId(0L);
            volume.setCatalog(Catalog.Manager);
            volume.setMenderId(0L);
            volume.setOwnerId(0L);
            volume.setGmtModify(new Date());
            volume.setExpiredTime(null);
            volume.setUuid(null);
            volumeRepository.update(volume);
            objectRelationRepository.deleteByRid(volume.getId(), ResourceCategory.Storage.name());
            if (isNotice) {
                volumeOrderMessage.setSn(orderItemSn);
                amqpTemplate.convertAndSend("resource.result.queue", volumeOrderMessage);
            }
        }
    }

    /**
     * 镜像分配
     *
     * @param userId
     * @param tenantId
     * @param projectId
     * @param image
     * @return
     * @throws Exception
     */
    public BocloudResult assignImage(Long userId, Long tenantId, Long projectId, Image image) throws Exception {
        ObjectRelation relation = objectRelationRepository.get(image.getId(), ResourceCategory.Image.name());
        Calendar calendar = Calendar.getInstance();
        if (null == relation) {
            relation = new ObjectRelation(userId, image.getId(), false, ResourceCategory.Image.name(),
                    Catalog.User.name(), 0);
            calendar.setTime(DateTools.stringToDateTime("2099-12-31 00:00:00"));
            relation.setExpiredTime(calendar.getTime());
            objectRelationRepository.save(relation);
        } else {
            relation.setTarget(userId);
            calendar.setTime(DateTools.stringToDateTime("2099-12-31 00:00:00"));
            relation.setExpiredTime(calendar.getTime());
            objectRelationRepository.update(relation);
        }
        image.setTenantId(tenantId);
        image.setProjectId(projectId);
        imageRepository.update(image);
        return new BocloudResult(true, "镜像分配成功");
    }

    /**
     * 分配云快照给租户用户
     *
     * @param userId
     * @param tenantId
     * @param projectId
     * @param snapshots
     * @return
     * @throws Exception
     */
    private BocloudResult assignSnapshot(Long userId, Long tenantId, Long projectId, List<Snapshot> snapshots, Long businessId)
            throws Exception {
        if (!ListTool.isEmpty(snapshots)) {
            Date stringToDateTime = DateTools.stringToDateTime("2099-12-31 00:00:00");
            for (Snapshot snapshot : snapshots) {
                snapshot.setExpiredTime(stringToDateTime);
                snapshot.setTenantId(tenantId);
                snapshot.setProjectId(projectId);
                snapshot.setCatalog(Catalog.User);
                snapshot.setMenderId(userId);
                snapshot.setOwnerId(userId);
                snapshot.setBusinessId(businessId);
                snapshotRepository.update(snapshot);
            }
        }
        return new BocloudResult(true, "云快照分配成功");
    }

    /**
     * 回收分配给租户的云快照
     *
     * @param snapshots
     * @param context
     * @throws Exception
     */
    private void recycleSnapshot(List<Snapshot> snapshots, RequestContext context, Boolean isNotice) throws Exception {
        if (!ListTool.isEmpty(snapshots)) {
            for (Snapshot snapshot : snapshots) {
                Long tenantId = snapshot.getTenantId();
                snapshot.setTenantId(0L);
                snapshot.setProjectId(0L);
                snapshot.setOwnerId(0L);
                snapshot.setCatalog(Catalog.Manager);
                snapshot.setMenderId(0L);
                snapshot.setGmtModify(new Date());
                snapshot.setExpiredTime(null);
                snapshotRepository.update(snapshot);

                if (null != tenantId && 0 != tenantId && isNotice) {
                    List<ResourceQuota> quotas = new ArrayList<>();
                    String snapshotServiceCode = "meta.snapshot";
                    quotas.add(new ResourceQuota(snapshotServiceCode, Long.valueOf(1)));
                    cosInternalService.updateQuotas(quotas, Action.Callback, tenantId);
                }

            }
        }
    }

    /**
     * 分配网络接口给租户用户
     *
     * @param userId
     * @param tenantId
     * @param projectId
     * @return
     * @throws Exception
     */
    private BocloudResult assignNetworkInterface(Long userId, Long tenantId, Long projectId,
                                                 List<NetworkInterface> networkInterfaces) throws Exception {
        if (!ListTool.isEmpty(networkInterfaces)) {
            for (NetworkInterface networkInterface : networkInterfaces) {
                networkInterface.setTenantId(tenantId);
                networkInterface.setProjectId(projectId);
                networkInterfaceRepository.update(networkInterface);
            }
        }
        return new BocloudResult(true, "网络接口分配成功");
    }

    /**
     * 回收分配给租户的网络接口
     *
     * @param networkInterfaces
     * @param menderId
     * @throws Exception
     */
    private void recycleNetworkInterface(List<NetworkInterface> networkInterfaces, Long menderId) throws Exception {
        if (!ListTool.isEmpty(networkInterfaces)) {
            for (NetworkInterface networkInterface : networkInterfaces) {
                networkInterface.setTenantId(0L);
                networkInterface.setProjectId(0L);
                networkInterface.setMenderId(menderId);
                networkInterface.setGmtModify(new Date());
                networkInterfaceRepository.update(networkInterface);
            }
        }
    }

    /**
     * 分配浮动IP给租户用户
     *
     * @param vendor
     * @param userId
     * @param tenantId
     * @param projectId
     * @param floatingIp
     * @param items
     * @param orderId
     * @param eipServiceCode
     * @return
     * @throws Exception
     */
    private BocloudResult assignFloatingIp(CloudVendor vendor, Long userId, Long tenantId, Long projectId,
                                           FloatingIp floatingIp, List<OrderItem> items, Long orderId, String eipServiceCode, Long businessId) throws Exception {
        // 下单
        BocloudResult<OrderItem> itemResult = resourceOrderService.createFipItem(orderId, eipServiceCode, floatingIp,
                vendor);
        if (itemResult.isFailed()) {
            return new BocloudResult(false, itemResult.getMessage());
        }
        OrderItem item = itemResult.getData();
        items.add(item);
        floatingIp.setExpiredTime(DateTools.stringToDateTime("2099-12-31 00:00:00"));
        floatingIp.setOwnerId(userId);
        floatingIp.setMenderId(userId);
        floatingIp.setProjectId(projectId);
        floatingIp.setTenantId(tenantId);
        floatingIp.setCatalog(Catalog.User);
        floatingIp.setUuid(item.getSn());
        floatingIp.setBusinessId(businessId);
        floatingIpRepository.update(floatingIp);
        return new BocloudResult(true, "浮动IP分配成功");
    }

    /**
     * 回收分配给项目的浮动IP
     *
     * @param floatingIp
     * @param context
     * @throws Exception
     */
    private void recycleFloatingIp(FloatingIp floatingIp, RequestContext context, Boolean isNotice) throws Exception {
        if (null != floatingIp) {
            String orderItemSn = floatingIp.getUuid();
            floatingIp.setProjectId(0L);
            floatingIp.setTenantId(0L);
            floatingIp.setOwnerId(0L);
            floatingIp.setMenderId(0L);
            floatingIp.setExpiredTime(null);
            floatingIp.setGmtModify(new Date());
            floatingIp.setUuid(null);
            floatingIpRepository.update(floatingIp);
            objectRelationRepository.deleteByRid(floatingIp.getId(), ResourceCategory.FloatingIp.name());
            if (isNotice) {
                OrderMessage orderMessage = new OrderMessage(orderItemSn, OrderMessage.Operation.Cancelation,
                        OrderItemStatus.UnsubscribeSuccess, null, "资源回收成功", null, null, new ArrayList<>(),
                        ResourceCategory.FloatingIp.name(), context);
                orderMessage.setCategory(ResourceCategory.FloatingIp.name());
                amqpTemplate.convertAndSend("resource.result.queue", orderMessage);
            }
        }
    }

}
