package com.bocloud.ims.service.common;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.entity.enums.BocloudStatus;
import com.bocloud.cmp.model.NotifyMessage;
import com.bocloud.cmp.model.ServerModel;
import com.bocloud.common.enums.BoCloudExchange;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.OperateResult;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.model.Result;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.IDFactory;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.resource.CloudServer;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.interfaces.resource.CloudServerService;
import com.bocloud.ims.repository.resource.CloudServerRepository;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import io.jsonwebtoken.lang.Assert;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AmqpTemplate;

import java.math.BigDecimal;

/**
 * @author wangyu
 * @version 5.1.0
 * @description 虚拟机创建抽象任务
 * @date: 2020-12-15
 */
@Slf4j
@NoArgsConstructor
public abstract class AbstractVmCreation {

    /**
     * 消息通知队列
     */
    private static final String NOTICE_QUEUE = "event.notice.queue";
    private static OperateResult.OperateCategory operateCategory = OperateResult.OperateCategory.ResourceEvent;
    public JSONObject params;
    public CloudVendor vendor;
    public RequestContext context;
    public CloudServerRepository serverRepository;
    public CloudServerService serverService;
    public AmqpTemplate amqpTemplate;
    public ResourceEventPublisher resourceEventPublisher;
    public ServerModel model;

    public AbstractVmCreation(JSONObject params, CloudVendor vendor, RequestContext context,
                              CloudServerRepository serverRepository, CloudServerService serverService, AmqpTemplate amqpTemplate,
                              ResourceEventPublisher resourceEventPublisher) {
        super();
        this.params = params;
        this.vendor = vendor;
        this.context = context;
        this.serverRepository = serverRepository;
        this.serverService = serverService;
        this.amqpTemplate = amqpTemplate;
        this.resourceEventPublisher = resourceEventPublisher;
    }

    /**
     * 参数校验
     *
     * @return
     */
    public abstract Result paramCheck();

    /**
     * 虚拟机创建参数封装
     *
     * @return
     */
    public abstract BocloudResult<ServerModel> prepare();

    /**
     * 虚拟机创建
     *
     * @param server
     * @param model
     * @return
     */
    public abstract BocloudResult<CloudServer> builder(CloudServer server, ServerModel model);

    /**
     * 处理订单
     *
     * @param server
     * @return
     */
    public abstract BocloudResult processOrder(CloudServer server);

    /**
     * 发送消息
     *
     * @param server
     * @param result
     */
    public void sendMessage(CloudServer server, BocloudResult result) {
        String operate = vendor.getType().toLowerCase() + ".vm";
        resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(), operate,
                MapTools.simpleMap(Common.VENDORID, vendor.getId()), operateCategory, context));
        NotifyMessage message = new NotifyMessage(context, "云主机创建", result.getMessage(), true, false);
        amqpTemplate.convertAndSend(BoCloudExchange.Default.DIRECT.getExchange(), NOTICE_QUEUE, message);
        // 发送给云平台统计队列对云平台重新统计
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(Common.VENDORID, server.getId());
        amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);
    }

    /**
     * 保存虚拟机基础数据
     *
     * @param model
     * @return
     */
    public CloudServer saveServer(ServerModel model) {
        CloudServer cloudServer = JSONObject.parseObject(JSONObject.toJSONString(params), CloudServer.class);
        cloudServer.setCpu(model.getCpu());
        cloudServer.setMemory(model.getMemory() == null ? new BigDecimal(0) : model.getMemory());
        cloudServer.setDisk(model.getDisk() == null ? 0 : model.getDisk());
        cloudServer.setPswd(model.getPassword());
        cloudServer.setAccount(model.getAccount());
        cloudServer.setZone(model.getZone());
        cloudServer.setStatus(BocloudStatus.Server.BUILDING.name());
        cloudServer.setIsTemplate(false);
        cloudServer.preSave(context.getTarget(), context.getTarget(), vendor.getId(), params.getLong("hostId"),
                model.getVdcId(), params.getLong("templateId"), context.getTenant(), context.getProject());
        cloudServer.setResourceId(IDFactory.instance().uuid());
        cloudServer.setVendorType(vendor.getType());
        cloudServer.setRecycle(false);
        cloudServer.setImageUuid(model.getImageUuid());
        cloudServer.setCatalog(context.getCatalog());
        cloudServer.setRegionId(model.getRegionId());
        cloudServer.setSecurityGroups(model.getSecurityGroups());
        cloudServer.setTenantId(params.getLong("tenantId"));
        cloudServer.setProjectId(params.getLong("projectId"));
        serverRepository.save(cloudServer);
        return cloudServer;
    }

    /**
     * 执行云主机创建任务，顺序是参数校验，参数封装，虚机创建，处理订单，发送消息
     *
     * @return
     */
    public BocloudResult execute() {
        try {
            Result result = paramCheck();
            Assert.isTrue(result.isSuccess(), result.getMessage());
            BocloudResult<ServerModel> prepareResult = prepare();
            Assert.isTrue(prepareResult.isSuccess(), prepareResult.getMessage());
            model = prepareResult.getData();
            // 保存虚拟机基础数据
            CloudServer server = saveServer(prepareResult.getData());
            BocloudResult<CloudServer> buildResult = builder(server, prepareResult.getData());
            Assert.isTrue(buildResult.isSuccess(), buildResult.getMessage());
            BocloudResult orderResult = processOrder(buildResult.getData());
            if (orderResult.isFailed()) {
                sendMessage(server, orderResult);
                // 处理订单失败逻辑
                serverService.remove(server.getId(), null, context);
                return new BocloudResult(false, orderResult.getMessage());
            }
            // 发送消息通知用户
            sendMessage(server, new BocloudResult(true, "云主机创建成功"));
            return new BocloudResult(true, "云主机创建成功");
        } catch (Exception e) {
            log.error("Get error message:{}", e);
            return new BocloudResult(false, e.getMessage());
        }
    }

}
