package com.bocloud.ims.service.builder;

import com.alibaba.fastjson.JSON;
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.BocloudResult;
import com.bocloud.common.model.RequestContext;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.ListTool;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.service.utils.PwdRandom;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class TceServerBuilder implements ServerBuilder {

    private CloudServerRepository cloudServerRepository;
    private ResourceRepository resourceRepository;
    private ResourceEventRepository resourceEventRepository;
    private ImageRepository imageRepository;
    private VolumeRepository volumeRepository;
    private ServerDriver serverDriver;
    private RequestContext context;
    private CloudVendor vendor;
    private ServerModel model;
    private VpcRepository vpcRepository;
    private FlavorRepository flavorRepository;
    private SubnetRepository subnetRepository;
    private KeypairRepository keypairRepository;
    private SecurityGroupRepository securityGroupRepository;
    private ServerSgroupRepository serverSgroupRepository;
    private ServerKeypairRepository serverKeypairRepository;

    public TceServerBuilder(CloudServerRepository cloudServerRepository, ResourceRepository resourceRepository,
                            ResourceEventRepository resourceEventRepository, ImageRepository imageRepository,
                            VolumeRepository volumeRepository, ServerDriver serverDriver, RequestContext context, CloudVendor vendor,
                            VpcRepository vpcRepository, FlavorRepository flavorRepository, SubnetRepository subnetRepository,
                            KeypairRepository keypairRepository, SecurityGroupRepository securityGroupRepository,
                            ServerSgroupRepository serverSgroupRepository, ServerKeypairRepository serverKeypairRepository) {
        super();
        this.cloudServerRepository = cloudServerRepository;
        this.resourceRepository = resourceRepository;
        this.resourceEventRepository = resourceEventRepository;
        this.imageRepository = imageRepository;
        this.volumeRepository = volumeRepository;
        this.serverDriver = serverDriver;
        this.context = context;
        this.vendor = vendor;
        this.vpcRepository = vpcRepository;
        this.flavorRepository = flavorRepository;
        this.subnetRepository = subnetRepository;
        this.keypairRepository = keypairRepository;
        this.securityGroupRepository = securityGroupRepository;
        this.serverSgroupRepository = serverSgroupRepository;
        this.serverKeypairRepository = serverKeypairRepository;
    }

    @Override
    public BocloudResult<ServerModel> prepare(JSONObject object) throws Exception {
        String name = object.getString(Common.NAME);// 云主机名
        String remark = object.getString("remark");// 描述
        String instanceChargeType = object.getString("period");
        if (null != instanceChargeType && "PREPAID".equalsIgnoreCase(instanceChargeType)) {
            return new BocloudResult<>(false, "包年包月业务暂未开放");
        }
        model = new ServerModel(name, remark);
        String regionId = object.getString("regionId");
        if (null != regionId && !"".equals(regionId)) {
            model.setRegionId(regionId);
        }
        String groups = object.getString("groups");
        if (null != groups && !"".equals(groups)) {
            List<String> securityGroups = JSON.parseArray(groups, String.class);
            model.setSecurityGroups(securityGroups);
        }
        model.setInstanceChargeType(instanceChargeType);

        Image image = imageRepository.query(object.getLong("imageId"));
        if (null == image) {
            return new BocloudResult<>(false, "镜像不存在");
        }

        String account = "root";
        if ("Windows".equalsIgnoreCase(image.getOsType())) {
            account = "Administrator";
        }
        Integer systemDiskSize = 0;
        if (object.containsKey("rootSize")) {
            systemDiskSize = object.getInteger("rootSize"); // 管理端可以指定系统盘大小
        } else if (object.containsKey("disk")) {
            Integer disk = object.getInteger("disk"); // 自服务端根据规格取系统盘大小
            int imageMinDisk = image.getMinDisk().intValue();
            if (disk < imageMinDisk) {
                return new BocloudResult<>(false, "系统盘大小能小于镜像盘大小");
            }
            systemDiskSize = disk;
        } else {
            systemDiskSize = image.getMinDisk().intValue(); // 容错
        }
        model.setDisk(systemDiskSize);
        String systemDiskCategory = object.getString("systemDiskCategory");

        String dataDisk = object.getString("dataDisk");
        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.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 networkId = null;
        String subnetUuid = null;
        Long vendorId = object.getLong("vendorId");
        Long subnetId = object.getLong("subnetId");
        Long vpcId = object.getLong("networkId");
        if (null != vpcId && vpcId > 0) {
            Vpc vpc = vpcRepository.query(vpcId);
            if (null != vpc) {
                networkId = vpc.getVpcId();
                Subnet subnet = subnetRepository.query(subnetId);
                if (null == subnet) {
                    return new BocloudResult<>(false, "子网信息异常！");
                }
                subnetUuid = subnet.getSubnetUuid();
            }
        }
        Flavor flavor = flavorRepository.query(object.getLong("flavorId"));
        if (null == flavor) {
            return new BocloudResult<>(false, "规格数据不存在！");
        }
        model.setCpu(flavor.getCpu());
        model.setMemory(flavor.getMemory());
        String keypairName = null;
        String keyName = object.getString("keypairName");
        if (null != keyName && !"".equals(keyName)) {
            Keypair keypair = keypairRepository.getByName(keyName, vendorId);
            if (null != keypair) {
                keypairName = keypair.getFingerprint();
            }
        }
        String password = object.getString("password");
        if (StringUtils.isEmpty(keypairName) && StringUtils.isEmpty(password)) {
            password = randomStr(12);
        }
        // 云主机标签
        if (!StringUtils.isEmpty(object.getString("labelIds"))) {
            List<Long> labelIds = JSONArray.parseArray(object.getString("labelIds"), Long.class);
            model.setLabelIds(labelIds);
        }
        String zone = object.getString("zone");
        if (StringUtils.isEmpty(zone)) {
            zone = object.getString("zoneId");
        }
        model.prepareData(account, password, zone, image.getImageUuid(), instanceChargeType, object.getString("groups"),
                systemDiskSize, null, flavor.getFlavorUuid(), networkId, subnetUuid, keypairName);
        model.setSystemDiskCategory(systemDiskCategory);
        model.setResourceLabel(object.getString("resourceLabel"));
        return new BocloudResult<ServerModel>(true, model, "success");
    }

    @Override
    public BocloudResult<CloudServer> builder(CloudServer cloudServer) throws Exception {
        // 创建云主机
        BocloudResult result = serverDriver.create(vendor.getUuid(), cloudServer.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.setInstanceId(server.getInstanceId());
            cloudServer.setUuid(server.getUuid());
            cloudServer.setDisk(server.getSystemDiskSize());
            cloudServer.setMemory(server.getMemory());
            cloudServer.setCpu(server.getCpu());
            cloudServer.setGmtVmCreate(server.getGmtVmCreate());
            cloudServer.setManagerIp(server.getManagerIp());
            cloudServer.setPrivateIps(server.getPrivateIps());
            cloudServer.setPublicIps(server.getPublicIps());
            cloudServer.setZone(server.getZone());
            cloudServer.setInstanceChargeType(server.getInstanceChargeType());
            cloudServer.setInternetChargeType(server.getInternetChargeType());
            cloudServer.setRegionId(server.getRegionId());
            cloudServer.setInternetMaxBandwidthOut(server.getInternetMaxBandwidthOut());
            cloudServer.setOsName(server.getOsName());
            cloudServer.setOsVersion(server.getOsVersion());
            cloudServer.setSubnetUuid(server.getSubnetUuid());
            cloudServer.setSystemDiskCategory(server.getSystemDiskCategory());
            cloudServer.setSystemDiskSize(server.getSystemDiskSize());
            cloudServer.setNetworkUuid(server.getNetworkUuid());
            cloudServer.setFlavorUuid(server.getFlavorUuid());
            cloudServer.setImageUuid(server.getImageUuid());
            cloudServer.setSecurityGroupId(JSON.toJSONString(model.getSecurityGroups()));
            cloudServer.setPswd(model.getPassword());
            cloudServer.setDisk(server.getSystemDiskSize());
            // 新创建的云主机 秘钥 同步不回来 所以直接采用model中的秘钥数据
            String keypairName = model.getKeypairName();
            if (null != keypairName && !"".equals(keypairName)) {
                List<String> keyPairList = new ArrayList<>();
                keyPairList.add(keypairName);
                cloudServer.setKeypairName(JSON.toJSONString(keyPairList));
            }
            // 系统类型、
            Image image = imageRepository.getByImageUuid(server.getImageUuid());
            if (null != image) {
                cloudServer.setOsCategory(image.getOsCategory());
            }
            String state = server.getStatus();
            if (state.equalsIgnoreCase(BocloudStatus.Server.RUNNING.name())) {
                cloudServer.setStatus(BocloudStatus.Server.RUNNING.name());
            } else if (state.equalsIgnoreCase(BocloudStatus.Server.STOPPED.name())) {
                cloudServer.setStatus(BocloudStatus.Server.STOPPED.name());
            }
            cloudServer.setRecycle(false);
            cloudServerRepository.update(cloudServer);
            List<Volume> volumeModels = server.getDiskDevices();
            if (!ListTool.isEmpty(volumeModels)) {
                for (Volume volume : volumeModels) {
                    Long tenantId = cloudServer.getTenantId();
                    volume.setCreatorId(userId);
                    volume.setGmtCreate(new Date());
                    volume.setVendorId(vendor.getId());
                    volume.setVendorType(vendor.getType());
                    volume.setTenantId(tenantId == null ? 0L : tenantId);
                    Long projectId = cloudServer.getProjectId();
                    if (null != projectId && projectId > 0) {
                        volume.setProjectId(projectId);
                    }
                    volume.setRegionId(server.getRegionId());
                    volume.setServerId(cloudServer.getId());
                    volume.setName(volume.getVolumeUuid());
                    volume.setServerId(cloudServer.getId());
                    volumeRepository.save(volume);
                }
            }
            List<Volume> listByServerId = volumeRepository.listByServerId(cloudServer.getId());
            if (null != listByServerId && listByServerId.size() > 0) {
                cloudServer.setDiskDevices(listByServerId);
            }

            List<String> secuList = JSONObject.parseArray(JSON.toJSONString(model.getSecurityGroups()), String.class);
            for (String securityGroup : secuList) {
                SecurityGroup group = securityGroupRepository.getByGroupId(securityGroup);
                ServerSgroup serverSgroup = new ServerSgroup(cloudServer.getId(), group.getId());
                serverSgroupRepository.save(serverSgroup);
            }
            // 保存 秘钥
            updateServerKeyPair(cloudServer, vendor.getId());
            // 保存资源
            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);
                }
            }
            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.setRegionId(cloudServer.getRegionId());
                resource.preSave(cloudServer.getName(), cloudServer.getStatus(), userId, context.getTenant());
                resource.setInventory(JSONObject.toJSONString(cloudServer));
                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.setPrivateIps(JSONObject.toJSONString(ips));
                resource.setRegionId(cloudServer.getRegionId());
                resourceRepository.update(resource);
            }
        } else {
            event = new ResourceEvent(cloudServer.getId(), handler, "成功", userId, new Date(), "VM", vendor.getId(),
                    context.getCatalog());
            cloudServerRepository.remove(cloudServer.getId(), context.getTarget());
        }
        resourceEventRepository.save(event);
        return result.isSuccess() ? new BocloudResult<>(true, cloudServer, "success")
                : new BocloudResult<>(false, cloudServer, result.getMessage());
    }

    private void updateServerKeyPair(CloudServer server, Long vendorId) throws Exception {
        String keypairName = server.getKeypairName();
        if (null != keypairName && !"".equals(keypairName) && !"null".equalsIgnoreCase(keypairName)) {
            List<String> keyPairList = JSON.parseArray(keypairName, String.class);
            ServerKeypair serverKeypair = null;
            for (String keyName : keyPairList) {
                if (null != keyName && !"".equals(keyName) && !"null".equalsIgnoreCase(keyName)) {
                    serverKeypair = new ServerKeypair();
                    Keypair keypair = keypairRepository.getByFingerprint(keyName, vendorId);
                    serverKeypair.setKeypairId(keypair.getId());
                    serverKeypair.setServerId(server.getId());
                    serverKeypairRepository.save(serverKeypair);
                }
            }
        }
    }

    /**
     * 返回随机字符串，同时包含数字、大小写字母
     *
     * @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);
    }

}
