package com.bocloud.ims.service.ecs;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.compute.ServerDriver;
import com.bocloud.cmp.entity.enums.BocloudStatus;
import com.bocloud.cmp.entity.enums.ResourceCategory;
import com.bocloud.cmp.entity.enums.VolumeCategory;
import com.bocloud.cmp.model.ServerModel;
import com.bocloud.common.enums.ResourceCatalog;
import com.bocloud.common.model.*;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.interfaces.resource.CloudServerService;
import com.bocloud.ims.interfaces.resource.ResourceAllocateService;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.service.common.AbstractVmCreation;
import com.bocloud.ims.service.utils.PwdRandom;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.google.common.collect.Lists;
import lombok.NoArgsConstructor;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

@Component
@NoArgsConstructor
@Scope("prototype")
public class TianyiVmCreation extends AbstractVmCreation {

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

    @Autowired
    private ImageRepository imageRepository;
    @Autowired
    private FlavorRepository flavorRepository;
    @Autowired
    private SubnetRepository subnetRepository;
    @Autowired
    private ServerDriver serverDriver;
    @Autowired
    private ServerLabelRepository serverLabelRepository;
    @Autowired
    private VolumeRepository volumeRepository;
    @Autowired
    private SecurityGroupRepository securityGroupRepository;
    @Autowired
    private ServerSgroupRepository serverSgroupRepository;
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private ResourceEventRepository resourceEventRepository;
    @Autowired
    private KeypairRepository keypairRepository;
    @Autowired
    private ServerKeypairRepository serverKeypairRepository;
    @Autowired
    private ResourceAllocateService resourceAllocateService;

    @Override
    public Result paramCheck() {
        Image image = imageRepository.query(params.getLong("imageId"));
        if (null == image) {
            return Result.FAILED("镜像不存在！");
        }
        params.put("osCategory", image.getOsCategory());
        params.put("imageUuid", image.getImageUuid());
        int imageMinDisk = image.getMinDisk().intValue();
        Integer systemDiskSize = params.getInteger("systemDiskSize");
        if (null == systemDiskSize) {
            systemDiskSize = params.getInteger("rootSize");
        }
        if (null == systemDiskSize || systemDiskSize < imageMinDisk) {
            return Result.FAILED("系统盘大小不允许小于镜像盘允许的最小值");
        }
        params.put("systemDiskSize", systemDiskSize);

        String instanceType = null;
        Flavor flavor = getFlavorId();
        if (null == flavor) {
            instanceType = params.getString("instanceType");
            if (StringUtils.isEmpty(instanceType)) {
                flavor = flavorRepository.query(params.getLong("flavorId"));
                if (null == flavor) {
                    return Result.FAILED("无效的规格参数！");
                }
                instanceType = flavor.getFlavorUuid();
            }
        } else {
            instanceType = flavor.getFlavorUuid();
        }
        if (StringUtils.isEmpty(instanceType)) {
            return Result.FAILED("不存在当前配置规格！");
        }
        params.put("instanceType", instanceType);

        String subnetUuid = params.getString("subnetId");
        if (!StringUtils.isEmpty(subnetUuid)) {
            Subnet subnet = subnetRepository.query(params.getLong("subnetId"));
            if (null == subnet) {
                return Result.FAILED("无效的子网参数！");
            }
            params.put("subnetUuid", subnet.getSubnetUuid());
        }
        return Result.SUCCESS("success");
    }

    public Flavor getFlavorId() {
        Long cpu = params.getLong("cpu");
        Long memory = params.getLong("memory");
        Long vendorId = params.getLong("vendorId");
        if (null == cpu || null == memory) {
            return null;
        }
        List<Param> parameter = Lists.newArrayList();
        // 匹配
        parameter.add(new Param(MapTools.simpleMap("cpu", cpu), Sign.EQ));
        parameter.add(new Param(MapTools.simpleMap("memory", memory), Sign.EQ));
        parameter.add(new Param(MapTools.simpleMap("family", "CPU_V5_GC"), Sign.EQ));
        parameter.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
        // 排序
        Map<String, String> sorter = new HashMap<>();
        sorter.put("cpu", "0");
        List<Flavor> flavors = flavorRepository.list(parameter, sorter);
        if (ListTool.isEmpty(flavors) || null == flavors.get(0)) {
            return null;
        }
        return flavors.get(0);
    }

    @Override
    public BocloudResult<ServerModel> prepare() {
        ServerModel model = new ServerModel();

        String name = params.getString(Common.NAME);// 虚拟机名
        String remark = params.getString("remark");// 描述
        model = new ServerModel(name, remark);
        Integer internetMaxBandwidthIn = params.getInteger("internetMaxBandwidthIn");
        Integer internetMaxBandwidthOut = params.getInteger("internetMaxBandwidthOut");
        if (null == internetMaxBandwidthIn || 0 == internetMaxBandwidthIn) {
            internetMaxBandwidthIn = 10;
        }
        if (null == internetMaxBandwidthOut || 0 == internetMaxBandwidthOut) {
            internetMaxBandwidthOut = 10;
        }
        model.setHostName("root");
        model.setImageType(params.getString("osCategory"));
        model.setDisk(params.getInteger("systemDiskSize"));
        model.setSystemDiskSize(params.getInteger("systemDiskSize"));
        // 虚拟机标签
        if (!StringUtils.isEmpty(params.getString("labelIds"))) {
            List<Long> labelIds = JSONArray.parseArray(params.getString("labelIds"), Long.class);
            model.setLabelIds(labelIds);
        }
        // 目前只有"SAS"、"SSD"
        model.setDiskType(params.getString("diskType"));

        String systemDiskCategory = params.getString("systemDiskCategory");
        if (VolumeCategory.CLOUD.name().equals(systemDiskCategory)) {
            systemDiskCategory = "cloud";
        } else if (VolumeCategory.EFFICIENCY.name().equals(systemDiskCategory)) {
            systemDiskCategory = "cloud_efficiency";
        } else if (VolumeCategory.SSD.name().equals(systemDiskCategory)) {
            systemDiskCategory = "cloud_ssd";
        }

        String dataDisk = params.getString("diskDevices");
        if (!StringUtils.isEmpty(dataDisk)) {
            JSONArray jsonArray = new JSONArray();
            List<Object> list = JSONArray.parseArray(dataDisk);
            for (Object obj : list) {
                JSONObject jsonObject = JSONObject.parseObject(obj.toString());
                String dataDiskCategory = jsonObject.getString("dataDiskCategory");
                if (dataDiskCategory != null && !"".equals(dataDiskCategory)) {
                    if (dataDiskCategory.equals(VolumeCategory.CLOUD.name())) {
                        jsonObject.put("dataDiskCategory", "cloud");
                    } else if (dataDiskCategory.equals(VolumeCategory.EFFICIENCY.name())) {
                        jsonObject.put("dataDiskCategory", "cloud_efficiency");
                    } else if (dataDiskCategory.equals(VolumeCategory.SSD.name())) {
                        jsonObject.put("dataDiskCategory", "cloud_ssd");
                    } else {
                        jsonObject.put("dataDiskCategory", "cloud");
                    }
                }
                jsonArray.add(jsonObject);
            }
            dataDisk = jsonArray.toJSONString();
        }
        String instanceChargeType = params.getString("instanceChargeType");
        if (null == instanceChargeType || "".equals(instanceChargeType)) {
            instanceChargeType = "PostPaid";
        }

        model.setName(params.getString("name"));
        model.setInstanceChargeType(instanceChargeType);
        model.setVpcUuid(params.getString("vpcId"));

        // 批量创建：外层有循环，这里直接写死给1
        model.setCount(1);
        model.setSubnetUuid(params.getString("subnetUuid"));

        String password = params.getString("password");
        String keypairName = params.getString("keypairName");
        // 如果未设置密码则随机生成并保存
        if (StringUtils.isEmpty(keypairName) && StringUtils.isEmpty(password)) {
            password = randomStr(12);
        }

        model.setKeypairName(keypairName);

        List<String> groups = JSONArray.parseArray(params.getString("groups"), String.class);
        model.setSecurityGroups(groups);

        model.prepareData("root", password, params.getString(Common.REGIONID), params.getString("zoneId"),
                params.getString("imageUuid"), params.getString("instanceType"), params.getString("groups"),
                params.getString("internetChargeType"), internetMaxBandwidthIn, internetMaxBandwidthOut,
                params.getInteger("systemDiskSize"), systemDiskCategory, dataDisk);
        return new BocloudResult<ServerModel>(true, model, "success");

    }

    @Override
    public BocloudResult<CloudServer> builder(CloudServer cloudServer, ServerModel model) {
        try {
            // 创建虚拟机
            BocloudResult result = serverDriver.create(vendor.getUuid(), model.getRegionId(), model);
            // 操作记录
            Long userId = context.getTarget();
            String handler = "虚拟机创建";
            ResourceEvent event = null;
            if (result.isSuccess()) {
                event = new ResourceEvent(cloudServer.getId(), handler, "成功", userId, new Date(), "VM", vendor.getId(),
                        context.getCatalog());
                String content = JSONObject.toJSONString(result.getData());
                CloudServer server = JSONObject.parseObject(content, CloudServer.class);
                cloudServer.setRegionId(server.getRegionId());
                cloudServer.setInstanceId(server.getInstanceId());
                cloudServer.setUuid(server.getUuid());
                cloudServer.setDisk(model.getDisk());
                cloudServer.setMemory(server.getMemory());
                cloudServer.setCpu(server.getCpu());
                cloudServer.setGmtVmCreate(server.getGmtVmCreate());
                cloudServer.setPrivateIps(server.getPrivateIps());
                cloudServer.setManagerIp(server.getPrivateIps());
                cloudServer.setFlavorUuid(server.getFlavorUuid());
                cloudServer.setOsName(server.getOsName());
                cloudServer.setRegionId(server.getRegionId());
                cloudServer.setNetcards(server.getNetcards());
                cloudServer.setVpcUuid(server.getVpcUuid());
                cloudServer.setSubnetUuid(server.getVSwitchId());

                cloudServer.setZone(model.getZone());
                cloudServer.setPswd(model.getPassword());
                String imageUuid = cloudServer.getImageUuid();
                Image image = imageRepository.queryByImageUuid(imageUuid);
                cloudServer.setImageUuid(imageUuid);
                cloudServer.setOsCategory(image.getOsCategory());
                cloudServer.setOsName(image.getOsName());
                cloudServer.setOsVersion(image.getOsVersion());
                String state = server.getStatus();
                if ("Running".equalsIgnoreCase(state)) {
                    cloudServer.setStatus(BocloudStatus.Server.RUNNING.name());
                } else if ("Stopped".equalsIgnoreCase(state)) {
                    cloudServer.setStatus(BocloudStatus.Server.STOPPED.name());
                }
                cloudServer.setRecycle(false);
                cloudServer.setPublicIps(server.getPublicIps());

                cloudServer.setLabelIds(server.getLabelIds());
                // 保存标签信息
                List<Long> labelIds = model.getLabelIds();
                if (!ListTool.isEmpty(labelIds)) {
                    List<ServerLabel> serverLabels = Lists.newArrayList();
                    for (Long labelId : labelIds) {
                        serverLabels.add(new ServerLabel(cloudServer.getId(), labelId, "VM", vendor.getId()));
                    }
                    if (!ListTool.isEmpty(serverLabels)) {
                        serverLabelRepository.batchSave(serverLabels);
                    }
                }

                serverRepository.update(cloudServer);
                List<Volume> volumeModels = server.getDiskDevices();
                if (!ListTool.isEmpty(volumeModels)) {
                    for (Volume volume : volumeModels) {
                        volume.setCreatorId(userId);
                        volume.setGmtCreate(new Date());
                        volume.setVendorId(vendor.getId());
                        volume.setVendorType(vendor.getType());
                        volume.setTenantId(cloudServer.getTenantId() == null ? 0L : cloudServer.getTenantId());
                        Long projectId = cloudServer.getProjectId();
                        if (null != projectId && projectId > 0) {
                            volume.setProjectId(projectId);
                        }
                        if (volume.getBootVolume()) {
                            volume.setBootVolume(true);
                            volume.setDeleteWithInstance(true);
                        } else {
                            volume.setBootVolume(false);
                            volume.setDeleteWithInstance(false);
                        }
                        volume.setServerId(cloudServer.getId());
                        volume.setRegionId(server.getRegionId());
                        volumeRepository.save(volume);
                    }
                }
                List<Volume> listByServerId = volumeRepository.listByServerId(cloudServer.getId());
                cloudServer.setDiskDevices(listByServerId);
                // 保存资源T
                List<String> ips = Lists.newArrayList();
                if (!StringUtils.isEmpty(server.getPrivateIps())) {
                    List<String> objects = JSONObject.parseArray(server.getPrivateIps(), String.class);
                    for (String ip : objects) {
                        ips.add(ip);
                    }
                }
                List<String> securityGroups = cloudServer.getSecurityGroups() == null ? new ArrayList<String>()
                        : cloudServer.getSecurityGroups();
                for (String securityGroup : securityGroups) {
                    SecurityGroup group = securityGroupRepository.getByGroupId(securityGroup, vendor.getId());
                    if (null != group) {
                        ServerSgroup serverSgroup = new ServerSgroup(cloudServer.getId(), group.getId());
                        serverSgroupRepository.save(serverSgroup);
                    }
                }
                // 保存 秘钥
                if (!StringUtils.isEmpty(model.getKeypairName())) {
                    updateServerKeyPair(cloudServer, vendor.getId(), model.getKeypairName());
                }
                Resource resource = resourceRepository.query(ResourceCategory.Computer.name(),
                        ResourceCatalog.LOGICAL.name(), cloudServer.getId());
                if (null == resource) {
                    resource = new Resource(ResourceCategory.Computer.name(), ResourceCatalog.LOGICAL.name(),
                            cloudServer.getId(), JSONObject.toJSONString(ips), cloudServer.getOsCategory(),
                            vendor.getId());
                    resource.preSave(cloudServer.getName(), cloudServer.getStatus(), userId, context.getTenant(),
                            context.getProject());
                    resource.setInventory(JSONObject.toJSONString(cloudServer));
                    resource.setRegionId(cloudServer.getRegionId());
                    resourceRepository.save(resource);
                } else {
                    resource.setInventory(JSONObject.toJSONString(cloudServer));
                    resource.setStatus(cloudServer.getStatus());
                    resource.setMenderId(userId);
                    resource.setCreatorId(userId);
                    resource.setGmtModify(new Date());
                    resource.setGmtCreate(new Date());
                    resource.setRegionId(cloudServer.getRegionId());
                    resource.setPrivateIps(JSONObject.toJSONString(ips));
                    resourceRepository.update(resource);
                }
            } else {
                event = new ResourceEvent(cloudServer.getId(), handler, "失败", userId, new Date(), "VM", vendor.getId(),
                        context.getCatalog());
                serverRepository.remove(cloudServer.getId(), context.getTarget());
            }
            resourceEventRepository.save(event);
            return result.isSuccess() ? new BocloudResult<>(true, cloudServer, "success")
                    : new BocloudResult<>(false, cloudServer, result.getMessage());
        } catch (Exception e) {
            return new BocloudResult<>(false, cloudServer, "虚机创建失败");
        }

    }

    private void updateServerKeyPair(CloudServer server, Long vendorId, String keyPairName) throws Exception {
        String keypairName = server.getKeypairName();
        if (null != keypairName && !"".equals(keypairName) && !"null".equalsIgnoreCase(keypairName)) {
            ServerKeypair serverKeypair = new ServerKeypair();
            Keypair keypair = keypairRepository.getByName(keyPairName, vendorId, server.getRegionId());
            if (null != keypair) {
                serverKeypair.setKeypairId(keypair.getId());
                serverKeypair.setServerId(server.getId());
                serverKeypairRepository.save(serverKeypair);
            }
        }
    }

    @Override
    public BocloudResult processOrder(CloudServer server) {
        JSONObject object = new JSONObject();
        object.put("id", server.getId());
        object.put("tenantId", server.getTenantId());
        object.put("projectId", server.getProjectId());
        object.put("skuId", server.getSkuId());
        object.put("month", params.getInteger("month"));
        return resourceAllocateService.assign(object, ResourceCategory.Computer, context);
    }

    /**
     * 返回随机字符串，同时包含数字、大小写字母
     *
     * @param len 字符串长度，不能小于3
     * @return String 随机字符串
     */
    public static String randomStr(int len) {
        if (len < 3) {
            throw new IllegalArgumentException("字符串长度不能小于3");
        }
        // 数组，用于存放随机字符
        char[] chArr = new char[len];
        // 为了保证必须包含数字、大小写字母
        chArr[0] = (char) ('0' + PwdRandom.uniform(0, 10));
        chArr[1] = (char) ('A' + PwdRandom.uniform(0, 26));
        chArr[2] = (char) ('a' + PwdRandom.uniform(0, 26));

        char[] codes = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
                'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
                'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
                'z'};
        // charArr[3..len-1]随机生成codes中的字符
        for (int i = 3; i < len; i++) {
            chArr[i] = codes[PwdRandom.uniform(0, codes.length)];
        }

        // 将数组chArr随机排序
        for (int i = 0; i < len; i++) {
            int r = i + PwdRandom.uniform(len - i);
            char temp = chArr[i];
            chArr[i] = chArr[r];
            chArr[r] = temp;
        }

        return new String(chArr);
    }

}
