package com.bocloud.ims.service.resource.contentlibrary;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.compute.ServerDriver;
import com.bocloud.cmp.driver.contentlibrary.LibraryDriver;
import com.bocloud.cmp.entity.enums.BocloudStatus;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.entity.enums.NetworkType;
import com.bocloud.cmp.model.*;
import com.bocloud.common.encrypt.AESEncrptor;
import com.bocloud.common.encrypt.Encryptor;
import com.bocloud.common.enums.BoCloudExchange;
import com.bocloud.common.model.*;
import com.bocloud.common.utils.*;
import com.bocloud.ims.entity.resource.*;
import com.bocloud.ims.entity.resource.contentlibrary.ContentLibrary;
import com.bocloud.ims.entity.resource.contentlibrary.ContentLibraryItem;
import com.bocloud.ims.interfaces.resource.CloudServerService;
import com.bocloud.ims.interfaces.resource.IpService;
import com.bocloud.ims.interfaces.resource.ResourceAllocateService;
import com.bocloud.ims.interfaces.resource.contentlibrary.ContentLibraryService;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.repository.resource.contentlibrary.ContentLibraryItemRepository;
import com.bocloud.ims.repository.resource.contentlibrary.ContentLibraryRepository;
import com.bocloud.ims.service.internal.CosInternalService;
import com.bocloud.ims.service.internal.SmsProjectService;
import com.bocloud.ims.service.utils.ResourceEventPublisher;
import com.bocloud.ims.service.utils.SyncVmwareUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import io.netty.util.internal.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.*;

/**
 * @author wangyu
 * @version 5.0.0-SNAPSHOT
 * @since 2021/2/26
 */
@Slf4j
@Service
public class ContentLibraryServiceImpl implements ContentLibraryService {

    private static final String NOTICE_QUEUE = "event.notice.queue";
    @Autowired
    private CloudVendorRepository vendorRepository;
    @Autowired
    private ContentLibraryRepository repository;
    @Autowired
    private ContentLibraryItemRepository itemRepository;
    @Autowired
    private VdcRepository vdcRepository;
    @Autowired
    private ClusterRepository clusterRepository;
    @Autowired
    private ServerRepository serverRepository;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private DataStoreRepository storeRepository;
    @Autowired
    private LibraryDriver driver;
    @Autowired
    private ResourceEventPublisher resourceEventPublisher;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private SmsProjectService smsProjectService;
    @Autowired
    private AmqpTemplate amqpTemplate;
    @Autowired
    private VolumeRepository volumeRepository;
    @Autowired
    private NetworkRepository networkRepository;
    @Autowired
    private SwitcherRepository switcherRepository;
    @Autowired
    private PortGroupRepository groupRepository;
    @Autowired
    private NetworkCardRepository networkCardRepository;
    @Autowired
    private NetworkHostRepository networkHostRepository;
    @Autowired
    private StoreHostRepository storeHostRepository;
    @Autowired
    private ServerDriver serverDriver;
    @Autowired
    private IpService ipService;
    @Autowired
    private CloudServerService serverService;
    @Autowired
    private PortGroupRepository portGroupRepository;
    @Autowired
    private ResourceAllocateService resourceAllocateService;
    @Autowired
    private CosInternalService cosInternalService;

    @Override
    public BocloudResult<GridBean<ContentLibrary>> list(Pager pager, RequestContext context) {
        try {
            List<ContentLibrary> list;
            int total;
            GridBean gridBean;
            pager.getSorter().put("gmtCreate", Common.ONE);
            List<Long> projectIds = new ArrayList<>();
            total = repository.count(pager.getParams(), projectIds);
            if (pager.getSimple()) {
                List<SimpleBean> beans = repository.list(pager.getParams(), pager.getSorter(), projectIds);
                gridBean = new GridBean(1, 1, total, beans);
            } else {
                list = repository.list(pager.getPage(), pager.getRows(), pager.getParams(), pager.getSorter(),
                        projectIds);
                gridBean = GridHelper.getBean(pager.getPage(), pager.getRows(), total, list);
            }
            return new BocloudResult(true, gridBean, "查询成功");
        } catch (Exception e) {
            log.error("Get error message：{}", e);
            return new BocloudResult(false, "查询失败");
        }
    }

    @Override
    public BocloudResult<GridBean<ContentLibraryItem>> listItems(Pager pager, RequestContext context) {
        try {
            List<ContentLibraryItem> list;
            int total;
            GridBean gridBean;
            pager.getSorter().put("gmtCreate", Common.ONE);
            List<Long> projectIds = new ArrayList<>();
            total = itemRepository.count(pager.getParams(), projectIds);
            if (pager.getSimple()) {
                List<SimpleBean> beans = itemRepository.list(pager.getParams(), pager.getSorter(), projectIds);
                gridBean = new GridBean(1, 1, total, beans);
            } else {
                list = itemRepository.list(pager.getPage(), pager.getRows(), pager.getParams(), pager.getSorter(),
                        projectIds);
                gridBean = GridHelper.getBean(pager.getPage(), pager.getRows(), total, list);
            }
            return new BocloudResult(true, gridBean, "查询成功");
        } catch (Exception e) {
            log.error("Get error message：{}", e);
            return new BocloudResult(false, "查询失败");
        }
    }

    @Override
    public BocloudResult deploy(ContentLibraryParam contentLibraryParam, RequestContext context) {
        CloudServer cloudServer = null;
        try {
            Long ovfItemId = contentLibraryParam.getOvfItemId();
            ContentLibraryItem item = itemRepository.query(ovfItemId);
            Assert.notNull(item, "OVF模板不存在");
            //如果需要添加到堡垒机并且模板密码没有维护
            if (StringUtil.isNullOrEmpty(item.getPassword())
                    && null != contentLibraryParam.getIsAddShterm()
                    && contentLibraryParam.getIsAddShterm()){
                return new BocloudResult(false, "模板暂未维护密码，请先维护或更换内容库模板");
            }
            CloudVendor vendor = vendorRepository.query(item.getVendorId());
            Assert.notNull(vendor, "云平台不存在");
            ServerModel model = JSONObject.parseObject(JSON.toJSONString(contentLibraryParam), ServerModel.class);
            Long vdcId = contentLibraryParam.getVdcId();
            Vdc vdc = vdcRepository.query(vdcId);
            Assert.notNull(vdc, "数据中心不存在");
            model.setVdcName(vdc.getName());
            model.setOvfItemId(item.getItemUuid());
            Long hostId = contentLibraryParam.getHostId();
            Server host = null;
            if (null == hostId) {
                List<Server> hosts = serverRepository.listByVdc(vdcId);
                Assert.notEmpty(hosts, "未找到合适的宿主机");
                host = hosts.get(new Random().nextInt(hosts.size()));
                hostId = host.getId();
                log.info("分配的宿主机：{}", host.getName());
                model.setHostName(host.getName());
                List<DataStore> stores = storeRepository.listByHost(hostId);
                Assert.notEmpty(stores, "未找到合适的数据存储");
                DataStore store = stores.get(new Random().nextInt(stores.size()));
                log.info("分配的存储：{}", store.getName());
                model.setDatastore(store.getName());
                // 查询虚拟机端口
                List<PortGroup> groups = Lists.newArrayList();
                List<Switcher> switchers = switcherRepository.listByHostId(hostId);
                for (Switcher switcher : switchers) {
                    List<PortGroup> portGroups = portGroupRepository.listBySwitcher(switcher.getId());
                    for (PortGroup portGroup : portGroups) {
                        if (portGroup.getType().equals(NetworkType.PortGroupType.VIRTUAL.name())) {
                            portGroup.setSwitchType(NetworkType.SwitchType.VSWITCH.name());
                            groups.add(portGroup);
                        }
                    }
                }
                List<NetworkHost> networkHosts = networkHostRepository.listByVhostId(hostId, "PM");
                // 查询分布式端口组
                for (NetworkHost networkHost : networkHosts) {
                    Network network = networkRepository.query(networkHost.getNetworkId());
                    if (null != network && null != network.getSwitcherId() && 0L != network.getSwitcherId()) {
                        List<PortGroup> portGroups = portGroupRepository.listBySwitcher(network.getSwitcherId());
                        for (PortGroup portGroup : portGroups) {
                            if (portGroup.getType().equals(NetworkType.PortGroupType.DVPORT.name())) {
                                Switcher switcher = switcherRepository.query(portGroup.getSwitcherId());
                                portGroup.setName(portGroup.getName());
                                portGroup.setSwitchName(switcher.getName());
                                portGroup.setSwitchType(switcher.getType());
                                groups.add(portGroup);
                            }
                        }
                    }
                }
                PortGroup portGroup = groups.get(0);
                model.setNicPortGroup(portGroup.getName());
                model.setNicPortType(portGroup.getType());
                log.info("自动根据宿主机分配的端口组：{}", JSONObject.toJSON(portGroup));
            } else {
                host = serverRepository.query(hostId);
                Assert.notNull(host, "宿主机不存在");
                model.setHostName(host.getName());
                DataStore store = storeRepository.query(contentLibraryParam.getStoreId());
                Assert.notNull(store, "数据存储不存在");
                model.setDatastore(store.getName());
                model.setNicPortGroup(contentLibraryParam.getNicPortGroup());
                model.setNicPortType(contentLibraryParam.getNicPortType());
            }
            if (null != host.getClusterId()) {
                Cluster cluster = clusterRepository.query(host.getClusterId());
                Assert.notNull(cluster, "宿主机所在集群不存在");
                model.setClusterName(cluster.getName());
            }
            cloudServer = JSONObject.parseObject(JSONObject.toJSONString(contentLibraryParam), CloudServer.class);
            cloudServer.setStatus(BocloudStatus.Server.BUILDING.name());
            cloudServer.setIsTemplate(false);
            cloudServer.preSave(context.getTarget(), context.getTarget(), vendor.getId(), host.getId(), vdc.getId(),
                    null, context.getTenant(), context.getProject());
            cloudServer.setResourceId(IDFactory.instance().uuid());
            cloudServer.setVendorType(vendor.getType());
            cloudServer.setRecycle(false);
            cloudServer.setCatalog(context.getCatalog());
            cloudServer.setTenantId(context.getTenant());
            cloudServer.setProjectId(context.getProject());
            Integer month = contentLibraryParam.getMonth();
            // 时长
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(new Date());
            if (null != month) {
                calendar.add(Calendar.MONTH, month);
            } else {
                calendar.setTime(DateTools.stringToDateTime("2099-12-31 00:00:00"));
            }
            cloudServer.setExpiredTime(calendar.getTime());
            cloudServerRepository.save(cloudServer);
            final CloudServer finalServer = cloudServer;
            final Server finalHost = host;
            taskExecutor.execute(() -> {
                try {
                    BocloudResult result = driver.ovfDeploy(model, vendor.getUuid());
                    List<Ip> ips = new ArrayList<>();
                    if (result.isSuccess()) {
                        String content = JSONObject.toJSONString(result.getData());
                        CloudServer server = JSONObject.parseObject(content, CloudServer.class);
                        List<Volume> diskDevices = server.getDiskDevices();
                        if (!ListTool.isEmpty(diskDevices)) {
                            for (Volume disk : diskDevices) {
                                disk.preSave(context.getTarget(), context.getTarget(), 0L, vendor.getId());
                                disk.setServerId(finalServer.getId());
                                disk.setCatalog(context.getCatalog());
                                disk.setProjectId(context.getProject());
                                disk.setTenantId(context.getTenant());
                                volumeRepository.save(disk);
                            }
                        }
                        finalServer.setInstanceId(server.getInstanceId());
                        finalServer.setUuid(server.getUuid());
                        finalServer.setToolsInstalled(
                                null == server.getToolsInstalled() ? false : server.getToolsInstalled());
                        finalServer
                                .setToolsRunning(null == server.getToolsRunning() ? false : server.getToolsRunning());
                        finalServer.setDatastores(server.getDatastores());
                        finalServer.setGmtVmCreate(server.getGmtVmCreate());
                        finalServer.setOsCategory(server.getOsCategory());
                        finalServer.setOsName(server.getOsName());
                        finalServer.setManagerIp(server.getManagerIp());
                        finalServer.setCpu(server.getCpu());
                        finalServer.setMemory(server.getMemory());
                        finalServer.setDisk(server.getDisk());
                        finalServer.setCpuHotEnable(server.getCpuHotEnable());
                        finalServer.setMemHotEnable(server.getMemHotEnable());
                        finalServer.setProps(model.getProps());
                        // 宿主机ID
                        finalServer.setHostId(model.getHostId());
                        // 宿主机名称
                        finalServer.setHostName(model.getHostName());
                        if (null != item.getPassword()) {
                            finalServer.setPassword(item.getPassword());
                        }
                        String state = server.getStatus();
                        if ("poweredOn".equalsIgnoreCase(state)) {
                            finalServer.setStatus(BocloudStatus.Server.RUNNING.name());
                        } else if ("poweredOff".equalsIgnoreCase(state)) {
                            finalServer.setStatus(BocloudStatus.Server.STOPPED.name());
                        } else if ("suspended".equalsIgnoreCase(state)) {
                            finalServer.setStatus(BocloudStatus.Server.SUSPENDED.name());
                        } else {
                            finalServer.setStatus(BocloudStatus.Server.EXCEPTION.name());
                        }
                        cloudServerRepository.update(finalServer);
                        // 同步新虚拟机下个对象信息
                        syncSubObject(finalServer, finalHost.getVdcId(), vendor.getId(), finalServer.getId(),
                                server.getStores(), server.getNetworks(), server.getNetcards(), context.getTarget());
                        // 分配IP地址
                        ServerModel customModel = new ServerModel();
                        customModel.setVdcName(vdc.getName());
                        customModel.setName(finalServer.getName());
                        List<NetworkCard> cards = networkCardRepository.listByHost(finalServer.getId(), "VM");
                        BocloudResult<List<Ip>> ipResult = ipService.achieveIps(Long.valueOf(cards.size()), "V4");
                        Assert.isTrue(ipResult.isSuccess(), ipResult.getMessage());
                        ips = ipResult.getData();
                        // 模板上的网卡
                        List<NetcardOperation> operations = new ArrayList<>();
                        for (int i = 0; i < cards.size(); i++) {
                            NetworkCard card = cards.get(i);
                            NetcardOperation operation = new NetcardOperation();
                            operation.setOperation("EDIT");
                            operation.setLabel(card.getLabel());
                            operation.setName(card.getName());
                            operation.setPortType(card.getPortType());
                            operation.setMac(card.getMac());
                            operation.setIp(JSONObject.parseObject(JSONObject.toJSONString(ips.get(i)), IpModel.class));
                            operations.add(operation);
                        }
                        customModel.setOperations(operations);
                        // 设置IP
                        BocloudResult customResult = serverDriver.customizationVm(vendor.getUuid(), null, customModel);
                        Assert.isTrue(customResult.isSuccess(), customResult.getMessage());
//						BocloudResult<ServiceSku> skuResult = cosInternalService.querySku("vmware.standard.server",
//								finalServer.getCpu().intValue(), finalServer.getMemory().intValue(),
//								finalServer.getDisk());
//						Assert.isTrue(skuResult.isSuccess(), skuResult.getMessage());
//						ServiceSku sku = skuResult.getData();
//						// 分配虚拟机
//						JSONObject object = new JSONObject();
//						object.put("id", finalServer.getId());
//						object.put("tenantId",
//								contentLibraryParam.getTenantId() == null ? 0 : contentLibraryParam.getTenantId());
//						object.put("projectId",
//								contentLibraryParam.getProjectId() == null ? 0 : contentLibraryParam.getProjectId());
//						object.put("skuId", sku.getId());
//						object.put("month", month);
//						log.info("虚拟机分配信息:{}", object.toJSONString());
//						BocloudResult allocateResult = resourceAllocateService.assign(object, ResourceCategory.Computer,
//								context);
//						Assert.isTrue(allocateResult.isSuccess(), allocateResult.getMessage());
                        // 开机
                        serverService.start(finalServer.getId(), context);
                    } else {
                        serverService.remove(finalServer.getId(), null, context);
                    }
                    String operate = vendor.getType().toLowerCase() + ".vm";
                    resourceEventPublisher.send(new OperateResult(result.isSuccess(), result.getMessage(), operate,
                            MapTools.simpleMap(Common.VENDORID, vendor.getId()),
                            OperateResult.OperateCategory.ResourceEvent, context));
                    NotifyMessage message = new NotifyMessage(context, "OVF部署云主机", result.getMessage(), true, false);
                    amqpTemplate.convertAndSend(BoCloudExchange.Default.DIRECT.getExchange(), NOTICE_QUEUE, message);
                    // 发送给云平台统计队列对云平台重新统计
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put(Common.VENDORID, vendor.getId());
                    amqpTemplate.convertAndSend("vendor.statistics.queue", jsonObject);
                    // 加入到堡垒机
                    if (null != contentLibraryParam.getIsAddShterm()
                            && contentLibraryParam.getIsAddShterm()
                            && finalServer.getVendorType().equals(CloudProvider.VMWARE.name())
                            && !ListTool.isEmpty(ips)
                            ) {
                        addShterm(finalServer, ips);
                    }
                } catch (Exception e) {
                    log.error("Get error message:{}", e);
                    resourceEventPublisher.send(new OperateResult(false, e.getMessage(),
                            vendor.getType().toLowerCase() + ".vm", MapTools.simpleMap(Common.VENDORID, vendor.getId()),
                            OperateResult.OperateCategory.ResourceEvent, context));
                    NotifyMessage message = new NotifyMessage(context, "OVF部署云主机", e.getMessage(), true, false);
                    amqpTemplate.convertAndSend(BoCloudExchange.Default.DIRECT.getExchange(), NOTICE_QUEUE, message);
                    serverService.remove(finalServer.getId(), null, context);
                }
            });
            return new BocloudResult(true, "通过OVF模板部署虚拟机任务已下发，正在执行...");
        } catch (Exception e) {
            log.error("Get error message:{}", e);
            return new BocloudResult(false, e.getMessage());
        }
    }

    /**
     * @param ipList
     * @return void
     * @Author: lxy
     * @Description: 把虚拟机加进平台纳管的堡垒机 -- 发送数据到mq
     * @Date 2021/5/13 21:17
     * @Param cloudServer
     * @throws:
     **/
    private void addShterm(CloudServer cloudServer, List<Ip> ipList) {
        for (Ip ip : ipList) {
            JSONObject jsonObject = new JSONObject();
            String type = cloudServer.getOsCategory().equalsIgnoreCase("LINUX") ? cloudServer.getOsCategory() : "WINDOWS";
            String username = cloudServer.getOsCategory().equalsIgnoreCase("LINUX") ? "root" : "administrator";
            jsonObject.put("name", cloudServer.getName());
            jsonObject.put("password", cloudServer.getPassword());
            jsonObject.put("privateIps", ip.getIp());
            jsonObject.put("username", username);
            jsonObject.put("type", type);
            log.info("vmware name is : {}, pwdDes is : {}", cloudServer.getName(), cloudServer.getPassword());
            amqpTemplate.convertAndSend("sync.shterm.queue", jsonObject);
            log.info("send rabbitmq topic is : {} success ，message is ：{}", "sync.shterm.queue",
                    jsonObject.toJSONString());
        }
    }

    @Override
    public BocloudResult<ContentLibrary> detail(Long id) {
        try {
            ContentLibrary library = repository.query(id);
            return null == library ? new BocloudResult(false, "数据不存在") : new BocloudResult(true, library, "查询成功");
        } catch (Exception e) {
            return new BocloudResult(false, e.getMessage());
        }
    }

    @Override
    public BocloudResult<ContentLibraryItem> detailItem(Long id) {
        try {
            ContentLibraryItem item = itemRepository.query(id);
            return null == item ? new BocloudResult(false, "数据不存在") : new BocloudResult(true, item, "查询成功");
        } catch (Exception e) {
            return new BocloudResult(false, e.getMessage());
        }
    }

    /**
     * 同步新虚拟机下的各对象信息
     *
     * @param cloudServer
     * @param vdcId
     * @param vendorId
     * @param serverId
     * @param datastores
     * @param networks
     * @param cards
     * @param userId
     * @throws Exception
     */
    private void syncSubObject(CloudServer cloudServer, Long vdcId, Long vendorId, Long serverId,
                               List<String> datastores, List<Network> networks, List<NetworkCard> cards, Long userId) throws Exception {
        // 数据中心的存储信息
        Map<String, DataStore> storeMap = new HashMap<>();
        List<DataStore> stores = storeRepository.listByVdc(vdcId);
        for (DataStore store : stores) {
            storeMap.put(store.getStoreVal(), store);
        }
        // 数据中心的网络信息
        Map<String, Network> networkMap = Maps.newHashMap();
        Map<String, String> groupMap = Maps.newHashMap();
        List<Network> oldNetworks = networkRepository.listByVdc(vdcId);
        for (Network network : oldNetworks) {
            networkMap.put(network.getNetworkVal(), network);
        }
        List<Switcher> switchers = switcherRepository.listByVdc(vdcId, "DVSWITCH");
        for (Switcher switcher : switchers) {
            List<PortGroup> groups = groupRepository.listBySwitcher(switcher.getId());
            for (PortGroup group : groups) {
                groupMap.put(group.getGroupVal(), switcher.getSwitcherVal());
            }
        }
        SyncVmwareUtils utils = new SyncVmwareUtils(storeRepository, serverRepository, networkRepository,
                storeHostRepository, networkCardRepository, groupRepository, networkHostRepository);
        // 同步存储
        log.info("Start to sync store......");
        utils.addStore(vendorId, serverId, userId, "VM", datastores, storeMap);
        log.info("End to sync store......");
        // 同步网络
        log.info("Start to sync network......");
        utils.addNetwork(vendorId, serverId, userId, "VM", networks, networkMap, groupMap);
        log.info("End to sync network......");
        // 同步网卡
        log.info("Start to sync network card......");
        utils.addCard(vendorId, serverId, userId, "VM", cards, Maps.newHashMap());
        log.info("End to sync network card......");
    }

    @Override
    public BocloudResult modifyAccount(Long id, String password, RequestContext context) {
        try {
            ContentLibraryItem server = itemRepository.query(id);
            server = Optional.ofNullable(server).orElseThrow(() -> new Exception("内容库模板不存在"));

            Encryptor encrptor = new AESEncrptor();
            server.setPswd(encrptor.decrypt(password, null));
            itemRepository.update(server);
            return new BocloudResult<>(true, "修改成功");
        } catch (Exception e) {
            log.error("Update server account error:", e.getMessage());
            return new BocloudResult<>(false, e.getMessage());
        }
    }
}
