package com.bocloud.ims.service.scheduler.scheduler;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.entity.enums.CloudProvider;
import com.bocloud.cmp.entity.enums.HmcPartitionType;
import com.bocloud.common.enums.Relation;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.common.model.Param;
import com.bocloud.common.model.Sign;
import com.bocloud.common.utils.Common;
import com.bocloud.common.utils.ListTool;
import com.bocloud.common.utils.MapTools;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.entity.resource.CloudVendorStatistics;
import com.bocloud.ims.entity.resource.Server;
import com.bocloud.ims.entity.resource.ServerConfig;
import com.bocloud.ims.entity.resource.f5.*;
import com.bocloud.ims.entity.resource.hmc.HmcPartition;
import com.bocloud.ims.entity.resource.hmc.HmcServer;
import com.bocloud.ims.repository.kubernetes.*;
import com.bocloud.ims.repository.resource.*;
import com.bocloud.ims.repository.resource.f5.*;
import com.bocloud.ims.repository.resource.hmc.HmcPartitionRepository;
import com.bocloud.ims.repository.resource.hmc.HmcServerRepository;
import com.bocloud.ims.repository.resource.horizon.*;
import com.bocloud.service.core.CurrentService;
import com.bocloud.service.lock.BocloudACLock;
import com.bocloud.service.lock.LockFactory;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/**
 * 云平台统计定时任务
 *
 * @author wangyu
 * @version 4.2.1-SNAPSHOT
 * @since 2019/11/4
 */
@Component
public class VendorStatisticsScheduler implements InitializingBean {

    private static final Logger logger = LoggerFactory.getLogger(VendorStatisticsScheduler.class);
    @Autowired
    private CloudVendorRepository cloudVendorRepository;
    @Autowired
    private CloudVendorStatisticsRepository cloudVendorStatisticsRepository;
    @Autowired
    private ClusterRepository clusterRepository;
    @Autowired
    private HmcServerRepository hmcServerRepository;
    @Autowired
    private HmcPartitionRepository hmcPartitionRepository;
    @Autowired
    private F5BiVirtualServerRepository f5BiVirtualServerRepository;
    @Autowired
    private F5BiPoolRepository f5BiPoolRepository;
    @Autowired
    private F5BiNodeRepository f5BiNodeRepository;
    @Autowired
    private SanFabricRepository sanFabricRepository;
    @Autowired
    private SanFabricZoneRepository sanFabricZoneRepository;
    @Autowired
    private F5BiProfileRepository f5BiProfileRepository;
    @Autowired
    private F5BiMonitorRepository f5BiMonitorRepository;
    @Autowired
    private KubeNamespaceRepository namespaceRepository;
    @Autowired
    private KubeNodeRepository nodeRepository;
    @Autowired
    private KubePodRepository podRepository;
    @Autowired
    private KubeServiceRepository serviceRepository;
    @Autowired
    private KubeDeploymentRepository deploymentRepository;
    @Autowired
    private CloudServerRepository cloudServerRepository;
    @Autowired
    private FlavorRepository flavorRepository;
    @Autowired
    private ServerRepository serverRepository;
    @Autowired
    private DataStoreRepository dataStoreRepository;
    @Autowired
    private VolumeRepository volumeRepository;
    @Autowired
    private ImageRepository imageRepository;
    @Autowired
    private NetworkRepository networkRepository;
    @Autowired
    private VpcRepository vpcRepository;
    @Autowired
    private MdiskRepository mdiskRepository;
    @Autowired
    private VolumePoolRepository volumePoolRepository;
    @Autowired
    private FlashCopyRepository flashCopyRepository;
    @Autowired
    private StorageHostRepository storageHostRepository;
    @Autowired
    private ResourceRepository resourceRepository;
    @Autowired
    private ResourceAuditRepository resourceAuditRepository;
    @Autowired
    private ServerConfigRepository serverConfigRepository;
    @Autowired
    private CurrentService service;
    @Autowired
    private LockFactory lockFactory;
    @Autowired
    private SnapshotRepository snapshotRepository;
    @Autowired
    private RouterRepository routerRepository;
    @Autowired
    private VmwareHorizonDesktopPoolRepository desktopPoolRepository;
    @Autowired
    private VmwareHorizonFarmRepository farmRepository;
    @Autowired
    private VmwareHorizonSessionRepository sessionRepository;
    @Autowired
    private VmwareHorizonUserOrGroupRepository userOrGroupRepository;
    @Autowired
    private VmwareHorizonVcenterRepository vcenterRepository;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    /**
     * 每10分钟定时跑一次任务
     *
     * @throws Exception
     */
    @Scheduled(cron = "${vendor.statistics.scheduler:0 1/10 * * * ?}")
    protected void process() throws Exception {
        if (!service.isLeader()) {
            return;
        }
        List<CloudVendor> vendors = cloudVendorRepository.listAll();
        if (ListTool.isEmpty(vendors)) {
            return;
        }
        List<Future<BocloudResult>> futures = new ArrayList<>();
        for (CloudVendor vendor : vendors) {
            futures.add(taskExecutor.submit(() -> this.summary(vendor)));
        }
        for (int i = 0; i < futures.size(); i++) {
            Future<BocloudResult> future = futures.get(i);
            BocloudResult result = future.get(10, TimeUnit.MINUTES);
            if (null != result) {
                logger.info(result.getMessage());
            }
        }
    }

    /**
     * 监听任务用来重新统计云平台使用情况
     *
     * @param message
     * @throws Exception
     */
    @RabbitListener(admin = "amqpAdmin", queues = "vendor.statistics.queue", autoStartup = "true")
    public void onMessage(Message message) throws Exception {
        if (!service.isLeader()) {
            return;
        }
        String content = new String(message.getBody(), "UTF-8");
        JSONObject result = JSONObject.parseObject(content);
        if (null == result) {
            return;
        }
        Long vendorId = result.getLong(Common.VENDORID);
        if (null == vendorId || 0L == vendorId) {
            return;
        }
        CloudVendor vendor = cloudVendorRepository.query(vendorId);
        if (null == vendor) {
            return;
        }
        // 重新统计云平台使用情况
        BocloudResult bocloudResult = this.summary(vendor);
        if (null != bocloudResult) {
            logger.info(bocloudResult.getMessage());
        }
    }

    /**
     * 云平台统计
     *
     * @param vendor
     * @return
     */
    private BocloudResult summary(CloudVendor vendor) {
        // 此处会修改堡垒机的主机数量,在此处不对堡垒机做任何统计操作
        if (CloudProvider.JUMPSERVER.name().equals(vendor.getType())) {
            return null;
        }
        String path = CloudVendorStatistics.class.getSimpleName() + "_" + vendor.getId();
        try (BocloudACLock lock = lockFactory.getACLock(path)) {
            Assert.isTrue(lock.acquire(20, TimeUnit.SECONDS), "请求超时");
            CloudVendorStatistics statistics = cloudVendorStatisticsRepository.queryByVendorId(vendor.getId());
            if (null == statistics) {
                statistics = new CloudVendorStatistics();
            }
            String type = StringUtils.isEmpty(vendor.getType()) ? "" : vendor.getType();
            Long vendorId = vendor.getId();
            if (type.equals(CloudProvider.HMC.name())) {
                // 服务器数量hostCount
                List<HmcServer> servers = hmcServerRepository.listByVendorId(vendorId);
                statistics.setHostCount(Long.valueOf(servers.size()));
                // VIOS分区的数量
                List<HmcPartition> partitions =
                        hmcPartitionRepository.listByVendorId(vendorId, HmcPartitionType.VIOS.getType());
                int viosCount = partitions.size();
                statistics.setViosCount(Long.valueOf(viosCount));
                // 所有逻辑分区数量
                partitions = hmcPartitionRepository.listByVendorId(vendorId, null);
                // 严格来说VIOS分区也是逻辑分区的一种，这里的逻辑分区特指出去VIOS分区外的其它逻辑分区
                statistics.setLparCount(Long.valueOf(partitions.size()) - viosCount);
            }
            if (type.equals(CloudProvider.F5.name())) {
                // virtual server的数量
                List<BiVirtualServer> biVirtualServers = f5BiVirtualServerRepository.list(vendorId);
                statistics.setVsCount(Long.valueOf(biVirtualServers.size()));
                // pool的数量
                List<BiPool> biPools = f5BiPoolRepository.list(vendorId);
                statistics.setPoolCount(Long.valueOf(biPools.size()));
                // node的数量
                List<BiNode> biNodes = f5BiNodeRepository.list(vendorId);
                statistics.setNodeCount(Long.valueOf(biNodes.size()));
                // profile的数量
                List<BiProfile> biProfiles = f5BiProfileRepository.list(vendorId);
                statistics.setProfileCount(Long.valueOf(biProfiles.size()));
                // monitor的数量
                List<BiMonitor> biMonitors = f5BiMonitorRepository.list(vendorId);
                statistics.setMonitorCount(Long.valueOf(biMonitors.size()));
            }
            // 统计数量
            List<Param> paramMap = Lists.newArrayList();
            if (CloudProvider.KUBERNETES.name().equals(vendor.getType())) {
                // namespace数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setNsCount(Long.valueOf(namespaceRepository.count(paramMap)));
                // node数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setNodeCount(new Long(nodeRepository.count(paramMap)));
                // node数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setPodCount(Long.valueOf(podRepository.count(paramMap)));
                // node数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setServiceCount(Long.valueOf(serviceRepository.count(paramMap)));
                // deployment数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setDeploymentCount(Long.valueOf(deploymentRepository.count(paramMap)));
            }
            Map<String, Object> map = MapTools.simpleMap("status", "RUNNING");
            map.put(Common.VENDORID, vendorId);
            paramMap.add(new Param(map, Sign.EQ));
            // 云主机数量
            int instance = cloudServerRepository.listByVid(vendorId).size();
            int online = cloudServerRepository.count(paramMap, 0L);
            statistics.setInstance(Long.valueOf(instance));
            statistics.setOnline(Long.valueOf(online));
            statistics.setOffline(Long.valueOf(instance) - online);
            // 模板数量
            map = MapTools.simpleMap(Common.VENDORID, vendorId);
            paramMap.clear();
            int template = 0;
            if (CloudProvider.OPENSTACK.name().equals(vendor.getType())
                    || CloudProvider.EASYSTACK.name().equals(vendor.getType())
                    || CloudProvider.FUSIONCLOUD.name().equals(vendor.getType())
                    || CloudProvider.MANAGEONE.name().equals(vendor.getType())) {
                paramMap.add(new Param(map, Sign.EQ));
                template = flavorRepository.count(paramMap);
            } else if (CloudProvider.POWERVC.name().equals(vendor.getType())) {
                map.put("status", "public");
                paramMap.add(new Param(map, Sign.EQ));
                template = flavorRepository.count(paramMap);
            } else if (CloudProvider.VMWARE.name().equals(vendor.getType()) ||
                    CloudProvider.H3C.name().equals(vendor.getType()) ||
                    CloudProvider.SMARTX.name().equals(vendor.getType()) ||
                    CloudProvider.FUSIONSPHERE.name().equals(type)) {
                map.put("isTemplate", 1);
                paramMap.add(new Param(map, Sign.EQ));
                template = cloudServerRepository.count(paramMap, 0L);
            }
            statistics.setTemplateCount(Long.valueOf(template));
            // 主机数量
            paramMap.clear();
            paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
            int count = serverRepository.countByLabel(paramMap, "");
            statistics.setHostCount(Long.valueOf(count));
            if (CloudProvider.VMWARE.name().equals(vendor.getType())) {
                // 存储数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setDataStoreCount(Long.valueOf(dataStoreRepository.count(paramMap)));
                // 集群数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setClusterCount(Long.valueOf(clusterRepository.count(paramMap)));
            } else if (CloudProvider.OPENSTACK.name().equals(vendor.getType())
                    || CloudProvider.EASYSTACK.name().equals(vendor.getType())
                    || CloudProvider.FUSIONCLOUD.name().equals(vendor.getType())
                    || CloudProvider.MANAGEONE.name().equals(vendor.getType())) {
                // 存储数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setDataStoreCount(Long.valueOf(volumeRepository.count(paramMap)));
                // 镜像数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setImageCount(Long.valueOf(imageRepository.count(paramMap, "")));
                // 网络数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setNetworkCount(Long.valueOf(networkRepository.count(paramMap, null)));
            } else if (CloudProvider.JDCLOUD.name().equals(vendor.getType()) || CloudProvider.ALIYUN.name()
                    .equals(vendor.getType()) || CloudProvider.TENCENT.name().equals(vendor.getType())
                    || CloudProvider.HUAWEI.name().equals(vendor.getType()) || CloudProvider.HCSO.name().equals(vendor.getType()) || CloudProvider.KINGCLOUD.name()
                    .equals(vendor.getType()) || CloudProvider.AZURE.name().equals(vendor.getType()) || CloudProvider.QCLOUD
                    .name().equals(vendor.getType()) || CloudProvider.AWS.name().equals(vendor.getType())
                    || CloudProvider.TCE.name().equals(vendor.getType()) || CloudProvider.TIANYI.name()
                    .equals(vendor.getType()) || CloudProvider.VOLCENGINE.name().equals(vendor.getType())) {
                // 镜像数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setImageCount(Long.valueOf(imageRepository.count(paramMap, "")));
                // 存储数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setDataStoreCount(Long.valueOf(volumeRepository.count(paramMap)));
                // VPC数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setVpcCount(Long.valueOf(vpcRepository.count(paramMap)));
                // 规格数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setTemplateCount(Long.valueOf(flavorRepository.count(paramMap)));
                statistics.setCpuTotal(Long.valueOf(cloudServerRepository.cpuSum(vendorId, null, null)));
                long memory = cloudServerRepository.memorySum(vendorId, null, null).longValue();
                statistics.setMemTotal(BigDecimal.valueOf(memory));
            } else if (CloudProvider.H3C.name().equals(vendor.getType())) {
                // 存储数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setDataStoreCount(Long.valueOf(dataStoreRepository.count(paramMap)));
                // 集群数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setClusterCount(Long.valueOf(clusterRepository.count(paramMap)));
            } else if (CloudProvider.POWERVC.name().equals(vendor.getType()) ||
                    CloudProvider.SMARTX.name().equals(vendor.getType())) {
                // 镜像数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setImageCount(Long.valueOf(imageRepository.count(paramMap, "")));
                // 存储数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setDataStoreCount(Long.valueOf(volumeRepository.count(paramMap)));
                // 集群数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setClusterCount(Long.valueOf(clusterRepository.count(paramMap)));
            } else if (CloudProvider.HORIZON.name().equals(type)) {
                // 桌面池
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setDesktopPools(Long.valueOf(desktopPoolRepository.count(paramMap)));
                // 场
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setFarms(Long.valueOf(farmRepository.count(paramMap)));
                // 会话
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setSessions(Long.valueOf(sessionRepository.count(paramMap)));
                // 用户
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setUsers(Long.valueOf(userOrGroupRepository.count(paramMap)));
                // vcenter
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setVcenters(Long.valueOf(vcenterRepository.count(paramMap)));
            } else if (CloudProvider.FUSIONSPHERE.name().equals(type)) {
                // fusionsphere统计 sxp:2022/7/28
                // 集群数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setClusterCount(Long.valueOf(clusterRepository.count(paramMap)));
                // 存储数量
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                statistics.setDataStoreCount(Long.valueOf(dataStoreRepository.count(paramMap)));
            } else if (CloudProvider.SANGFOR.name().equals(type)){
                paramMap.clear();
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                paramMap.add(new Param(MapTools.simpleMap("type", "VS"), Sign.EQ));

                paramMap.add(new Param(Relation.OR,MapTools.simpleMap("is_deleted", 0), Sign.EQ));
                paramMap.add(new Param(MapTools.simpleMap(Common.VENDORID, vendorId), Sign.EQ));
                paramMap.add(new Param(MapTools.simpleMap("type", "OTHER"), Sign.EQ));
                statistics.setDataStoreCount(Long.valueOf(dataStoreRepository.count(paramMap)));
            }
            if (CloudProvider.VMWARE.name().equals(vendor.getType()) ||
                    CloudProvider.OPENSTACK.name().equals(vendor.getType()) ||
                    CloudProvider.EASYSTACK.name().equals(vendor.getType()) ||
                    CloudProvider.SMARTX.name().equals(vendor.getType())) {
                List<Server> hosts = serverRepository.listByVendor(vendorId);
                int cpuTotal = 0;
                double memTotal = 0;
                int cpuCount = 0;
                for (Server host : hosts) {
                    ServerConfig config = serverConfigRepository.getBySid(host.getId());
                    if (null != config) {
                        cpuTotal += (null == config.getCpuHz()) ? 0 : config.getCpuHz();
                        memTotal += (null == config.getMemoryCapacity()) ? 0 : config.getMemoryCapacity();
                        cpuCount += (null == config.getCpuCore() ? 0 : config.getCpuCore());
                    }
                }
                statistics.setCpuTotal(Long.valueOf(cpuTotal));
                statistics.setCpuCount(Long.valueOf(cpuCount));
                statistics.setMemTotal(BigDecimal.valueOf(memTotal));
            }
            statistics.setVendorId(vendor.getId());
            if (null == statistics.getId() || 0L == statistics.getId()) {
                cloudVendorStatisticsRepository.save(statistics);
            } else {
                cloudVendorStatisticsRepository.update(statistics);
            }
            return new BocloudResult(true, "云平台【" + vendor.getName() + "】数据统计完成！");
        } catch (Exception e) {
            logger.error("Get error message：{}", e);
            return new BocloudResult(false, "云平台【" + vendor.getName() + "】数据统计发生异常！");
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.process();
    }
}
