package com.bocloud.ims.service.resource;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.bocloud.ims.service.task.ResourceTaskNotice;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.compute.ServerDriver;
import com.bocloud.cmp.driver.compute.ServerTemplateDriver;
import com.bocloud.cmp.driver.storage.VolumeDriver;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.model.IpModel;
import com.bocloud.cmp.model.NetcardOperation;
import com.bocloud.cmp.model.NetworkCardModel;
import com.bocloud.cmp.model.ServerModel;
import com.bocloud.cmp.model.ServerTemplateModel;
import com.bocloud.cmp.model.VolumeModel;
import com.bocloud.cmp.vm.model.VmGenericParam;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.GridBean;
import com.bocloud.common.model.OperateResult;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.model.Sign;
import com.bocloud.common.model.SimpleBean;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.GridHelper;
import com.bocloud.common.utils.JSONTools;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.common.Project;
import com.bocloud.ims.entity.resource.CloudServer;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.Image;
import com.bocloud.ims.entity.resource.Network;
import com.bocloud.ims.entity.resource.Server;
import com.bocloud.ims.entity.resource.ServerTemplate;
import com.bocloud.ims.entity.resource.ServerTemplateVersion;
import com.bocloud.ims.entity.resource.Subnet;
import com.bocloud.ims.entity.resource.Switcher;
import com.bocloud.ims.entity.resource.VendorTaskMsg;
import com.bocloud.ims.entity.resource.Volume;
import com.bocloud.ims.interfaces.resource.ServerTemplateService;
import com.bocloud.ims.repository.resource.CloudServerRepository;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.bocloud.ims.repository.resource.ImageRepository;
import com.bocloud.ims.repository.resource.NetworkCardRepository;
import com.bocloud.ims.repository.resource.NetworkRepository;
import com.bocloud.ims.repository.resource.ServerImageRepository;
import com.bocloud.ims.repository.resource.ServerRepository;
import com.bocloud.ims.repository.resource.ServerTemplateRepository;
import com.bocloud.ims.repository.resource.ServerTemplateVersionRepository;
import com.bocloud.ims.repository.resource.ServerVolumeRepository;
import com.bocloud.ims.repository.resource.SubnetRepository;
import com.bocloud.ims.repository.resource.SwitcherRepository;
import com.bocloud.ims.repository.resource.VolumeRepository;
import com.bocloud.ims.repository.resource.VolumeTemplateRepository;
import com.bocloud.ims.service.builder.ServerBuilder;
import com.bocloud.ims.service.internal.SmsProjectService;
import com.bocloud.ims.service.model.ProcessResult;
import com.bocloud.ims.service.transporter.vendor.SmartxTransporter;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.ims.service.utils.ServerOperationHelper;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * 云主机模板
 *
 * @author ymh
 * @时间 2019年3月9日
 */
@Service("serverTemplateService")
public class ServerTemplateServiceImpl implements ServerTemplateService {

    private static Logger logger = LoggerFactory.getLogger(ServerTemplateServiceImpl.class);
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private ServerTemplateDriver serverTemplateDriver;
    @Autowired
    private ServerDriver serverDriver;
    @Autowired
    private VolumeDriver volumeDriver;
    @Autowired
    private ServerTemplateRepository serverTemplateRepository;
    @Autowired
    private ServerTemplateVersionRepository serverTemplateVersionRepository;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private VolumeRepository volumeRepository;
    @Autowired
    private VolumeTemplateRepository volumeTemplateRepository;
    @Autowired
    private ImageRepository imageRepository;
    @Autowired
    private NetworkRepository networkRepository;
    @Autowired
    private SubnetRepository subnetRepository;
    @Autowired
    private SwitcherRepository switcherRepository;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private SmartxTransporter smartTransporter;
    @Autowired
    private SmsProjectService smsProjectService;
    @Autowired
    private ServerVolumeRepository serverVolumeRepository;
    @Autowired
    private ServerImageRepository serverImageRepository;
    @Autowired
    private NetworkCardRepository networkCardRepository;
    @Autowired
    private ServerRepository serverRepository;
    @Autowired
    private ServerOperationHelper serverOperationHelper;
    @Autowired
    private ResourceTaskNotice resourceTaskNotice;

    @Override
    public BocloudResult list(int page, int rows, List<Param> params, Map<String, String> sorter, boolean simple,
                              RequestContext context) {
        List<ServerTemplate> list = Lists.newArrayList();
        int total = 0;
        GridBean gridBean = null;
        try {
            if (null == params) {
                params = new ArrayList<>();
            }
            if (null == sorter) {
                sorter = Maps.newHashMap();
            }
            sorter.put("gmtCreate", Common.ONE);
            Long tenantId = context.getTenant();
            Long projectId = context.getProject();
            // 为租户下的用户
            if (null != tenantId && 0L != tenantId) {
                List<Project> projects = smsProjectService.projectsByCondition(context.getTarget(),
                        context.getCatalog());
                List<Long> projectIds = new ArrayList<>();
                // 此时查询的是全部用户全部项目的信息
                if (null != projectId && 0L != projectId) {
                    projectIds.add(projectId);
                } else if (!ListTool.isEmpty(projects)) {
                    projects.forEach(project -> projectIds.add(project.getId()));
                } else {
                    // 当前用户不属于任何项目，则登录之后查看不到任何信息
                    projectIds.add(-1L);
                }
                total = serverTemplateRepository.count(params, projectIds);
                list = serverTemplateRepository.list(page, rows, params, sorter, projectIds);
                gridBean = GridHelper.getBean(page, rows, total, list);
            } else {
                total = serverTemplateRepository.count(params);
                if (simple) {
                    if (0 == tenantId) {
                        params.add(new Param(MapTools.simpleMap(Common.TENANTID, 0), Sign.EQ));
                    }
                    List<SimpleBean> beans = serverTemplateRepository.list(params, sorter);
                    gridBean = new GridBean(1, 1, total, beans);
                } else {
                    list = serverTemplateRepository.list(page, rows, params, sorter, null);
                    gridBean = GridHelper.getBean(page, rows, total, list);
                }
            }
            return new BocloudResult<>(true, gridBean, "查询成功");
        } catch (Exception e) {
            logger.error("list volume failure:", e);
            return new BocloudResult<>(false, "查询失败", null, null);
        }
    }

    private BocloudResult createSmart(ServerTemplateModel templateModel, RequestContext context) {
        try {
            Assert.notNull(templateModel.getVendorId(), "需要参数vendorId");
            CloudVendor vendor = cloudVendorRepository.query(templateModel.getVendorId());
            Assert.notNull(vendor, "id为" + templateModel.getVendorId() + "云平台不存在");

            ServerTemplateModel paramModel = new ServerTemplateModel();

            Assert.notNull(templateModel.getName(), "需要为云主机模板指定名称");
            CloudServer vmbyName = cloudServerRepository.getByName(templateModel.getName(), vendor.getId());
            Assert.isNull(vmbyName, "名为" + templateModel.getName() + "的云主机模板已经存在，请重新命名");
            paramModel.setName(templateModel.getName());

            if (templateModel.getHa() == null) {
                templateModel.setHa(true);
            }
            paramModel.setHa(templateModel.getHa());

            Assert.notNull(templateModel.getCpu(), "需要为云主机模板指定CPU配置");
            paramModel.setCpu(templateModel.getCpu());

            Assert.notNull(templateModel.getMemory(), "需要为云主机模板指定内存配置");
            paramModel.setMemory(templateModel.getMemory());

            Assert.notNull(templateModel.getFirmware(), "需要为云主机模板指定引导选项");
            paramModel.setFirmware(templateModel.getFirmware());

            if (StringUtils.isNotEmpty(templateModel.getRemark())) {
                paramModel.setRemark(templateModel.getRemark());
            }

            Assert.notEmpty(templateModel.getVolumeModels(), "需要为云主机模板定义虚拟盘");
            List<VolumeModel> disks = new ArrayList<>();
            for (VolumeModel diskDevice : templateModel.getVolumeModels()) {
                VolumeModel disk = new VolumeModel();

                if ("mountDisk".equals(diskDevice.getType())) {
                    disk.setType("disk");

                    Assert.notNull(diskDevice.getId(), "需要指定要挂载的虚拟卷");
                    Volume volume = volumeRepository.query(diskDevice.getId());
                    Assert.notNull(volume, "id为" + diskDevice.getId() + "的虚拟卷不存在");
                    disk.setPath(volume.getPath());

                    Assert.notNull(diskDevice.getBus(), "需要为新建的虚拟卷指定总线");
                    disk.setBus(diskDevice.getBus());
                } else if ("mountISO".equals(diskDevice.getType())) {
                    disk.setType("cdrom");
                    disk.setBus("ide");

                    Assert.notNull(diskDevice.getId(), "需要指定要挂载的ISO映像");
                    Image image = imageRepository.query(diskDevice.getId());
                    Assert.notNull(image, "id为" + diskDevice.getId() + "的ISO映像不存在");
                    disk.setPath(image.getFilePath());

                    Assert.notNull(diskDevice.getDisabled(), "需要参数diskDevices.disabled");
                    disk.setDisabled(diskDevice.getDisabled());
                } else {
                    return new BocloudResult<>(false, "未知的虚拟盘类型");
                }
                disks.add(disk);
            }
            paramModel.setVolumeModels(disks);

            Assert.notEmpty(templateModel.getNetworkCardModels(), "需要为云主机模板定义虚拟网卡");
            List<NetworkCardModel> networkCards = new ArrayList<>();
            for (NetworkCardModel netcard : templateModel.getNetworkCardModels()) {
                NetworkCardModel networkCard = new NetworkCardModel();

                Assert.notNull(netcard.getNetworkId(), "需要为虚拟网卡指定网络");
                Network network = networkRepository.query(netcard.getNetworkId());
                Assert.notNull(network, "未找到id为" + netcard.getNetworkId() + "的虚拟网络");
                networkCard.setNetworkUuid(network.getNetworkUuid());

                Switcher switcher = switcherRepository.query(network.getSwitcherId());
                Assert.notNull(switcher, "未找到id为" + network.getSwitcherId() + "的虚拟交换机");
                networkCard.setOvsbrName(switcher.getOvsbrName());

                List<Subnet> subnet = subnetRepository.listByNetwork(network.getId());
                Assert.notEmpty(subnet, "未在网络" + network.getName() + "下找到任何子网");
                networkCard.setVlan(subnet.get(0).getVlan());

                Assert.notNull(netcard.getLink(), "参数operation.link不能为空");
                networkCard.setUsed("up".equals(netcard.getLink()));

                networkCards.add(networkCard);
            }
            paramModel.setNetworkCardModels(networkCards);

            taskExecutor.execute(() -> {
                String messagePrefix = "创建云主机模板" + templateModel.getName();
                String path = vendor.getType() + "." + vendor.getId() + ".template";
                OperateResult result = new OperateResult(true, "", "template.create", null, OperateResult.OperateCategory.ResourceEvent, context);
                try (BocloudACLock lock = lockFactory.getACLock(path)) {
                    Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "当前存在其他互斥任务，请稍后再试");

                    BocloudResult bocloudResult = serverTemplateDriver.create(vendor.getUuid(), null, paramModel);
                    if (bocloudResult.isSuccess()) {
                        String taskUuid = bocloudResult.getData().toString();
                        VendorTaskMsg taskMsg = smartTransporter.getTask(vendor, taskUuid, context.getTarget());
                        bocloudResult = new BocloudResult(taskMsg.getSmartSucceed(), taskMsg.getSmartFinalErrorMessage());
                        if (bocloudResult.isSuccess()) {
                            bocloudResult = serverTemplateDriver.detail(vendor.getUuid(), null, taskMsg.getTargetUuid());
                        }
                    }
                    if (bocloudResult.isFailed()) {
                        result.setSuccess(false);
                        result.setMessage(messagePrefix + "失败：" + bocloudResult.getMessage());
                        resourceEventPublisher.send(result);
                        return;
                    }

                    ServerModel serverModel = (ServerModel) bocloudResult.getData();
                    CloudServer cloudServer = new CloudServer();
                    smartTransporter.convert(serverModel, cloudServer);
                    cloudServer.setVendorId(vendor.getId());
                    cloudServer.setVendorType(vendor.getType());
                    cloudServer.setCreatorId(context.getTarget());
                    cloudServer.setGmtCreate(new Date());
                    cloudServerRepository.save(cloudServer);

                    smartTransporter.syncNetworkCard(cloudServer, serverModel.getNetworkCards(), context.getTarget());

                    List<VolumeModel> imageModels = serverModel.getDiskDevices().stream()
                            .filter(d -> "cdrom".equals(d.getType())).collect(Collectors.toList());
                    smartTransporter.syncServerImage(cloudServer, imageModels, context.getTarget());

                    List<VolumeModel> volumeModels = serverModel.getDiskDevices().stream()
                            .filter(d -> "disk".equals(d.getType())).collect(Collectors.toList());
                    smartTransporter.syncServerVolume(cloudServer, volumeModels, context.getTarget());

                    Image image = new Image();
                    smartTransporter.convert(serverModel, image);
                    image.setVendorId(vendor.getId());
                    image.setTemplateId(cloudServer.getId());
                    image.setCreatorId(context.getTarget());
                    image.setGmtCreate(new Date());
                    imageRepository.save(image);

                    result.setSuccess(true);
                    result.setMessage(messagePrefix + "成功");
                    resourceEventPublisher.send(result);
                } catch (Exception e) {
                    result.setSuccess(false);
                    result.setMessage(messagePrefix + "失败：" + e.getMessage());
                    resourceEventPublisher.send(result);
                }
            });
            return new BocloudResult(true, "任务已经下发，正在执行...");
        } catch (Exception e) {
            logger.error("创建云主机模板失败: {}", e.getMessage(), e);
            return new BocloudResult<>(false, "创建云主机模板失败: " + e.getMessage());
        }
    }

    /**
     * 创建云主机模板
     *
     * @param templateModel
     * @param context
     * @return
     */
    @Override
    public BocloudResult create(ServerTemplateModel templateModel, RequestContext context) {
        try {
            Assert.notNull(templateModel.getVendorId(), "需要参数vendorId");
            CloudVendor vendor = cloudVendorRepository.query(templateModel.getVendorId());
            Assert.notNull(vendor, "id为" + templateModel.getVendorId() + "云平台不存在");
            if (CloudProvider.SMARTX.name().equals(vendor.getType())) {
                return createSmart(templateModel, context);
            }
            BocloudResult bocloudResult = serverTemplateDriver.create(vendor.getUuid(),
                    templateModel.getRegion(), templateModel);
            return new BocloudResult<>(bocloudResult.isSuccess(), bocloudResult.getMessage());
        } catch (Exception e) {
            logger.error("get cloudvendor and reg error:", e);
            return new BocloudResult<>(false, "创建失败!");
        }
    }

    public BocloudResult modifySmart(ServerTemplateModel templateModel, RequestContext context) {
        try {
            Assert.notNull(templateModel.getVendorId(), "需要参数vendorId");
            CloudVendor vendor = cloudVendorRepository.query(templateModel.getVendorId());
            Assert.notNull(vendor, "id为" + templateModel.getVendorId() + "云平台不存在");

            ServerTemplateModel paramModel = new ServerTemplateModel();

            Assert.notNull(templateModel.getId(), "需要参数id");
            CloudServer cloudServer = cloudServerRepository.query(templateModel.getId());
            Assert.notNull(cloudServer, "id为" + templateModel.getId() + "云主机模板不存在");

            paramModel.setTemplateUuid(cloudServer.getInstanceId());

            if (StringUtils.isNotEmpty(templateModel.getName())) {
                paramModel.setName(templateModel.getName());
            } else {
                paramModel.setName(cloudServer.getName());
            }

            if (StringUtils.isNotEmpty(templateModel.getRemark())) {
                paramModel.setRemark(templateModel.getRemark());
            } else {
                paramModel.setRemark(cloudServer.getRemark());
            }

            taskExecutor.execute(() -> {
                String messagePrefix = "修改云主机模板" + templateModel.getName();
                String path = ServerTemplate.class.getName() + "." + paramModel.getTemplateUuid();
                OperateResult result = new OperateResult(true, "", "template.modify", null, OperateResult.OperateCategory.ResourceEvent, context);
                try (BocloudACLock lock = lockFactory.getACLock(path)) {
                    Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "当前存在其他互斥任务，请稍后再试");

                    BocloudResult bocloudResult = serverTemplateDriver.modify(vendor.getUuid(), null, paramModel);
                    if (bocloudResult.isFailed()) {
                        result.setSuccess(false);
                        result.setMessage(messagePrefix + "失败：" + bocloudResult.getMessage());
                        resourceEventPublisher.send(result);
                        return;
                    }

                    cloudServer.setName(paramModel.getName());
                    cloudServer.setRemark(paramModel.getRemark());
                    cloudServerRepository.update(cloudServer);

                    Image image = imageRepository.getByImageUuid(cloudServer.getInstanceId());
                    image.setName(paramModel.getName());
                    image.setRemark(paramModel.getRemark());
                    imageRepository.update(image);

                    result.setSuccess(true);
                    result.setMessage(messagePrefix + "成功");
                    resourceEventPublisher.send(result);
                } catch (Exception e) {
                    result.setSuccess(false);
                    result.setMessage(messagePrefix + "失败：" + e.getMessage());
                    resourceEventPublisher.send(result);
                }
            });
            return new BocloudResult(true, "任务已经下发，正在执行...");
        } catch (Exception e) {
            logger.error("修改云主机模板失败: {}", e.getMessage(), e);
            return new BocloudResult<>(false, "修改云主机模板失败: " + e.getMessage());
        }
    }

    @Override
    public BocloudResult modify(ServerTemplateModel templateModel, RequestContext context) {
        try  {
            if (templateModel.getVendorId() != null) {
                CloudVendor vendor = cloudVendorRepository.query(templateModel.getVendorId());
                Assert.notNull(vendor, "id为" + templateModel.getVendorId() + "云平台不存在");
                if (CloudProvider.SMARTX.name().equals(vendor.getType())) {
                    return modifySmart(templateModel, context);
                }
            }
            ServerTemplate serverTemplate = serverTemplateRepository.query(templateModel.getId());
            if (null == serverTemplate) {
                logger.warn("volume data not exist");
                return new BocloudResult<>(false, "数据不存在");
            }
            CloudVendor cloudVendor = cloudVendorRepository.query(serverTemplate.getVendorId());
            if (null == cloudVendor) {
                logger.error("get cloudVendor failure!");
                return new BocloudResult<>(false, "云平台不存在!");
            }
            ServerTemplateModel serverTemplateModel = new ServerTemplateModel();
            BocloudResult bocloudResult = serverTemplateDriver.modify(cloudVendor.getUuid(),
                    serverTemplate.getRegion(), serverTemplateModel);
            return new BocloudResult<>(bocloudResult.isSuccess(), bocloudResult.getMessage());
        } catch (Exception e) {
            logger.error("Modify serverTemplate fail:", e);
            return new BocloudResult<>(false, "修改失败");
        }
    }

    private BocloudResult removeSmart(Long id, Long vendorId, RequestContext context) {
        try {
            Assert.notNull(vendorId, "需要参数vendorId");
            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            Assert.notNull(vendor, "id为" + vendorId + "云平台不存在");

            ServerTemplateModel paramModel = new ServerTemplateModel();

            Assert.notNull(id, "需要参数id");
            CloudServer cloudServer = cloudServerRepository.query(id);
            Assert.notNull(cloudServer, "id为" + id + "云主机模板不存在");

            paramModel.setTemplateUuid(cloudServer.getInstanceId());
            paramModel.setName(cloudServer.getName());

            taskExecutor.execute(() -> {
                String messagePrefix = "删除云主机模板" + paramModel.getName();
                String path = ServerTemplate.class.getName() + "." + paramModel.getTemplateUuid();
                OperateResult result = new OperateResult(true, "", "template.remove", null, OperateResult.OperateCategory.ResourceEvent, context);
                try (BocloudACLock lock = lockFactory.getACLock(path)) {
                    Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "当前存在其他互斥任务，请稍后再试");

                    BocloudResult bocloudResult = serverTemplateDriver.remove(vendor.getUuid(), null, paramModel);
                    if (bocloudResult.isSuccess()) {
                        String taskUuid = bocloudResult.getData().toString();
                        VendorTaskMsg taskMsg = smartTransporter.getTask(vendor, taskUuid, context.getTarget());
                        bocloudResult = new BocloudResult(taskMsg.getSmartSucceed(), taskMsg.getSmartFinalErrorMessage());
                    }
                    if (bocloudResult.isFailed()) {
                        result.setSuccess(false);
                        result.setMessage(messagePrefix + "失败：" + bocloudResult.getMessage());
                        resourceEventPublisher.send(result);
                        return;
                    }

                    cloudServerRepository.remove(cloudServer.getId(), context.getTarget());
                    networkCardRepository.removeByHost(cloudServer.getId(), "VM", context.getTarget());
                    serverVolumeRepository.removeBySid(cloudServer.getId());
                    serverImageRepository.removeBySid(cloudServer.getId());

                    imageRepository.removeByTemplate(cloudServer.getId(), context.getTarget());

                    result.setSuccess(true);
                    result.setMessage(messagePrefix + "成功");
                    resourceEventPublisher.send(result);
                } catch (Exception e) {
                    result.setSuccess(false);
                    result.setMessage(messagePrefix + "失败：" + e.getMessage());
                    resourceEventPublisher.send(result);
                }
            });
            return new BocloudResult(true, "任务已经下发，正在执行...");
        } catch (Exception e) {
            logger.error("删除云主机模板失败: {}", e.getMessage(), e);
            return new BocloudResult<>(false, "删除云主机模板失败: " + e.getMessage());
        }
    }

    @Override
    public BocloudResult remove(Long id, Long vendorId, RequestContext context) {
        if (vendorId != null) {
            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            Assert.notNull(vendor, "id为" + vendorId + "云平台不存在");
            if (CloudProvider.SMARTX.name().equals(vendor.getType())) {
                return removeSmart(id, vendorId, context);
            }
            return new BocloudResult(false, "尚未实现");
        } else {
            String path = ServerTemplate.class.getSimpleName() + "_" + id;
            try (BocloudACLock lock = lockFactory.getACLock(path)) {
                Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
                ServerTemplate serverTemplate = serverTemplateRepository.query(id);
                if (null == serverTemplate) {
                    logger.warn("volume data not exist");
                    return new BocloudResult<>(false, "数据不存在");
                }
                CloudVendor cloudVendor = cloudVendorRepository.query(serverTemplate.getVendorId());
                if (null == cloudVendor) {
                    logger.error("get cloudVendor failure!");
                    return new BocloudResult<>(false, "云平台不存在!");
                }
                ServerTemplateModel serverTemplateModel = new ServerTemplateModel();
                serverTemplateModel.setTemplateUuid(serverTemplate.getTemplateUuid());
                BocloudResult bocloudResult = serverTemplateDriver.remove(cloudVendor.getUuid(),
                        serverTemplate.getRegion(), serverTemplateModel);
                if (bocloudResult.isFailed()) {
                    return new BocloudResult<>(false, bocloudResult.getMessage());
                }
                serverTemplateRepository.remove(serverTemplate.getId(), context.getTarget());
                return new BocloudResult<>(bocloudResult.isSuccess(), "删除成功！");
            } catch (Exception e) {
                logger.error("remove volume fail:", e);
                return new BocloudResult<>(false, "删除失败");
            }
        }
    }

    @Override
    public BocloudResult detail(Long id, Long vendorId, RequestContext context) {
        try {
            if (vendorId != null) {
                CloudVendor vendor = cloudVendorRepository.query(vendorId);
                Assert.notNull(vendor, "id为" + vendorId + "云平台不存在");
                if (CloudProvider.SMARTX.name().equals(vendor.getType())) {
                    CloudServer cloudServer = cloudServerRepository.query(id);
                    return new BocloudResult<>(true, cloudServer, "查询详情成功");
                } else {
                    ServerTemplate serverTemplate = serverTemplateRepository.query(id);
                    return new BocloudResult<>(true, serverTemplate, "查询详情成功");
                }
            } else {
                ServerTemplate serverTemplate = serverTemplateRepository.query(id);
                return new BocloudResult<>(true, serverTemplate, "查询详情成功");
            }
        } catch (Exception e) {
            logger.error("query volume detail fail:", e);
            return new BocloudResult<>(false, "查询详情失败");
        }
    }

    @Override
    public BocloudResult createTempalteVersion(String params, RequestContext context) {
        JSONObject object = JSONTools.isJSONObj(params);
        Long vendorId = object.getLong(Common.VENDORID);
        String regionId = object.getString("regionId");
        try {
            CloudVendor cloudVendor = cloudVendorRepository.query(vendorId);
            if (null == cloudVendor) {
                logger.error("get cloudVendor failure!");
                return new BocloudResult<>(false, "云平台不存在!");
            }
            ServerTemplateModel serverTemplateModel = new ServerTemplateModel();
            BocloudResult bocloudResult = serverTemplateDriver.create(cloudVendor.getUuid(), regionId,
                    serverTemplateModel);
            return new BocloudResult<>(bocloudResult.isSuccess(), bocloudResult.getMessage());
        } catch (Exception e) {
            logger.error("get cloudvendor and reg error:", e);
            return new BocloudResult<>(false, "创建失败!");
        }
    }

    @Override
    public BocloudResult modifyDafaultVersion(String params, Long userId) {
        JSONObject object = JSONTools.isJSONObj(params);
        Long versionId = object.getLong(Common.ID);
        String path = ServerTemplate.class.getSimpleName() + "_" + versionId;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            ServerTemplateVersion serverTemplateVersion = serverTemplateVersionRepository.query(versionId);
            if (null == serverTemplateVersion) {
                logger.warn("volume data not exist");
                return new BocloudResult<>(false, "版本不存在！");
            }
            CloudVendor cloudVendor = cloudVendorRepository.query(serverTemplateVersion.getVendorId());
            if (null == cloudVendor) {
                logger.error("get cloudVendor failure!");
                return new BocloudResult<>(false, "云平台不存在!");
            }
            ServerTemplate serverTemplate = serverTemplateRepository.queryByUuid(cloudVendor.getId(),
                    serverTemplateVersion.getTemplateUuid());
            ServerTemplateModel serverTemplateModel = new ServerTemplateModel();
            serverTemplateModel.setDefaultVersionNumber(serverTemplateVersion.getVersionNumber());
            serverTemplateModel.setTemplateUuid(serverTemplateVersion.getTemplateUuid());
            BocloudResult bocloudResult = serverTemplateDriver.modifyDefaultVersion(cloudVendor.getUuid(),
                    serverTemplateVersion.getRegion(), serverTemplateModel);
            if (bocloudResult.isFailed()) {
                return new BocloudResult<>(false, bocloudResult.getMessage());
            }
            serverTemplateVersion.setDefaultVersion(true);
            serverTemplateVersionRepository.update(serverTemplateVersion);

            serverTemplate.setDefaultVersionNumber(serverTemplateVersion.getVersionNumber());
            serverTemplateRepository.update(serverTemplate);
            return new BocloudResult<>(bocloudResult.isSuccess(), bocloudResult.getMessage());
        } catch (Exception e) {
            logger.error("Modify serverTemplate fail:", e);
            return new BocloudResult<>(false, "修改失败");
        }
    }

    @Override
    public BocloudResult removeTemplateVersion(String params, RequestContext context) {
        JSONObject object = JSONTools.isJSONObj(params);
        Long defaultVersionId = object.getLong(Common.ID);
        String path = ServerTemplate.class.getSimpleName() + "_" + defaultVersionId;
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "请求超时");
            ServerTemplateVersion serverTemplateVersion = serverTemplateVersionRepository.query(defaultVersionId);
            if (null == serverTemplateVersion) {
                logger.warn("serverTemplateVersion data not exist");
                return new BocloudResult<>(false, "数据不存在");
            }
            CloudVendor cloudVendor = cloudVendorRepository.query(serverTemplateVersion.getVendorId());
            if (null == cloudVendor) {
                logger.error("get cloudVendor failure!");
                return new BocloudResult<>(false, "云平台不存在!");
            }
            ServerTemplateModel serverTemplateModel = new ServerTemplateModel();
            serverTemplateModel.setTemplateUuid(serverTemplateVersion.getTemplateUuid());
            List<Long> versions = new ArrayList<>();
            versions.add(serverTemplateVersion.getVersionNumber());
            serverTemplateModel.setVersions(versions);
            BocloudResult bocloudResult = serverTemplateDriver.removeTemplateVersion(cloudVendor.getUuid(),
                    serverTemplateVersion.getRegion(), serverTemplateModel);
            if (bocloudResult.isFailed()) {
                return new BocloudResult<>(false, bocloudResult.getMessage());
            }
            return new BocloudResult<>(bocloudResult.isSuccess(), "删除成功！");
        } catch (Exception e) {
            logger.error("remove volume fail:", e);
            return new BocloudResult<>(false, "删除失败");
        }
    }

    private BocloudResult createVmSmart(Long id, Long vendorId, String action, ServerTemplateModel params, RequestContext context) {
        try {

            Assert.notNull(id, "需要指定源云主机模板");
            CloudServer template = cloudServerRepository.query(id);
            Assert.notNull(template, "id为" + id + "云主机模板不存在");
            CloudVendor vendor = cloudVendorRepository.query(template.getVendorId());
            Assert.notNull(vendor, "id为" + template.getVendorId() + "云平台不存在");
            CloudProvider provider = CloudProvider.valueOf(vendor.getType());

            VmGenericParam vmGenericParam = JSON.parseObject(JSON.toJSONString(params), VmGenericParam.class);
            vmGenericParam.setId(null);
            vmGenericParam.setCount(1);
            vmGenericParam.setTemplateId(id);
            vmGenericParam.setVmHostName(params.getVmHostname());
            vmGenericParam.setPassword(params.getPassword());
            vmGenericParam.setDiskDevices(params.getVolumeModels());

            List<NetcardOperation> operations = new ArrayList<>();
            for (NetworkCardModel networkCardModel : params.getNetworkCardModels()) {
                NetcardOperation netcardOperation = JSON.parseObject(JSON.toJSONString(networkCardModel), NetcardOperation.class);
                if (StringUtils.isEmpty(networkCardModel.getIpAddress())) {
                    netcardOperation.setIpPolicy("Auto");
                } else {
                    netcardOperation.setIpPolicy("Manual");
                    IpModel ipModel = new IpModel();
                    ipModel.setIp(networkCardModel.getIpAddress());
                    ipModel.setMask(networkCardModel.getNetmask());
                    netcardOperation.setIp(ipModel);
                }
                operations.add(netcardOperation);
            }
            vmGenericParam.setOperations(operations);

            BocloudResult<ServerBuilder> getProcessResult = serverOperationHelper.getProcess(provider, vendor, context);
            Assert.isTrue(getProcessResult.isSuccess(), getProcessResult.getMessage());
            ServerBuilder serverBuilder = getProcessResult.getData();

            BocloudResult<ProcessResult> prepareResult = serverOperationHelper.prepare(vmGenericParam, context, vendor, serverBuilder);
            Assert.isTrue(prepareResult.isSuccess(), prepareResult.getMessage());
            final ProcessResult processResult = prepareResult.getData();

            taskExecutor.execute(() -> {
                String prefix = "从模板" + template.getName() + "创建云主机";
                String path = CloudServer.class.getSimpleName() + "_" + template.getId();
                OperateResult operateResult = new OperateResult(true, "", "template.createVm",
                        MapTools.simpleMap(Common.VENDORID, vendor.getId()),
                        OperateResult.OperateCategory.ResourceEvent, context);
                try (BocloudACLock lock = lockFactory.getACLock(path)) {
                    Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "当前存在互斥任务，请稍后再试");

                    BocloudResult<CloudServer> buildResult = serverOperationHelper.builder(vendor.getType(),
                            vendor.getId(), processResult.getCloudServer(), context, serverBuilder, null);
                    Assert.isTrue(buildResult.isSuccess(), buildResult.getMessage());

                    operateResult.setSuccess(true);
                    operateResult.setMessage(prefix + "成功");
                    resourceEventPublisher.send(operateResult);
                } catch (Exception e) {
                    logger.error(prefix + "失败：{}", e.getMessage(), e);
                    operateResult.setSuccess(false);
                    operateResult.setMessage(prefix + "失败：" + e.getMessage());
                    resourceEventPublisher.send(operateResult);
                }
            });
            return new BocloudResult<>(true, "任务已经下发，正在执行...");
        } catch (Exception e) {
            logger.error("从模板创建云主机失败：{}", e.getMessage(), e);
            return new BocloudResult<>(false, "从模板创建云主机失败" + e.getMessage());
        }
    }

    private BocloudResult asVmSmart(Long id, Long vendorId, String action, ServerTemplateModel param, RequestContext context) {
        try {
            Assert.notNull(vendorId, "需要参数vendorId");
            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            Assert.notNull(vendor, "id为" + vendorId + "云平台不存在");

            Assert.notNull(id, "需要参数id");
            CloudServer cloudServer = cloudServerRepository.query(id);
            Assert.notNull(cloudServer, "id为" + id + "云主机模板不存在");

            Assert.notNull(param.getName(), "需要指定目标云主机名称");
            CloudServer vmbyName = cloudServerRepository.getByName(param.getName(), vendor.getId());
            Assert.isTrue(vmbyName == null || vmbyName.getIsTemplate(),
                    "名为" + param.getName() + "的云主机已经存在，请重新命名");

            ServerModel serverModel = new ServerModel();
            serverModel.setInstanceId(cloudServer.getInstanceId());
            serverModel.setName(param.getName());

            taskExecutor.execute(() -> {
                String messagePrefix = "从模板" + cloudServer.getName() + "创建云主机";
                String path = ServerTemplate.class.getName() + "." + cloudServer.getInstanceId();
                OperateResult result = new OperateResult(true, "", "template.asVm", null,
                        OperateResult.OperateCategory.ResourceEvent, context);
                try (BocloudACLock lock = lockFactory.getACLock(path)) {
                    Assert.isTrue(lock.acquire(10, TimeUnit.SECONDS), "当前存在其他互斥任务，请稍后再试");

                    BocloudResult bocloudResult = serverTemplateDriver
                            .asServer(vendor.getUuid(), null, serverModel.getInstanceId(), serverModel);
                    Assert.isTrue(bocloudResult.isSuccess(), bocloudResult.getMessage());

                    bocloudResult = serverDriver.detail(cloudServer.getInstanceId(), vendor.getUuid(), null);
                    Assert.isTrue(bocloudResult.isSuccess(), bocloudResult.getMessage());

                    ServerModel resultModel = (ServerModel) bocloudResult.getData();

                    String serverIp = resultModel.getServerVal();
                    Server host = serverRepository.queryBy3Ip(serverIp);
                    Assert.notNull(host, "未找到IP为" + serverIp + "的主机");

                    smartTransporter.convert(resultModel, cloudServer);
                    cloudServer.setHostId(host.getId());
                    cloudServer.setIsTemplate(false);
                    cloudServerRepository.update(cloudServer);
                    //通知cop
                    resourceTaskNotice.sendLogicalMessage(cloudServer, ResourceTaskNotice.Action.UPDATE);
                    imageRepository.removeByTemplate(cloudServer.getId(), context.getTarget());

                    result.setSuccess(true);
                    result.setMessage(messagePrefix + "成功");
                    resourceEventPublisher.send(result);
                } catch (Exception e) {
                    logger.error(messagePrefix + "失败：{}", e.getMessage(), e);
                    result.setSuccess(false);
                    result.setMessage(messagePrefix + "失败：" + e.getMessage());
                    resourceEventPublisher.send(result);
                }
            });
            return new BocloudResult(true, "任务已经下发，正在执行...");
        } catch (Exception e) {
            logger.error("将模板转化为云主机失败: {}", e.getMessage(), e);
            return new BocloudResult<>(false, "将模板转化为云主机失败: " + e.getMessage());
        }
    }

    @Override
    public BocloudResult operate(Long id, Long vendorId, String action, ServerTemplateModel param, RequestContext context) {
        CloudVendor vendor = cloudVendorRepository.query(vendorId);
        Assert.notNull(vendor, "id为" + vendorId + "云平台不存在");
        if (CloudProvider.SMARTX.name().equals(vendor.getType())) {
            if ("createVm".equalsIgnoreCase(action)) {
                return createVmSmart(id, vendorId, action, param, context);
            } else if ("asVm".equalsIgnoreCase(action)) {
                return asVmSmart(id, vendorId, action, param, context);
            } else {
                return new BocloudResult(false, "不支持的操作");
            }
        }
        return new BocloudResult(false, "尚未实现");
    }
}
