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

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.ims.entity.resource.f5.*;
import com.bocloud.ims.interfaces.resource.f5.F5NetworkMapService;
import com.bocloud.ims.repository.resource.f5.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Created by liuyuanyuan on 2019/5/6 15:19
 */
@Service("f5NetworkMapService")
public class F5NetworkMapServiceImpl implements F5NetworkMapService {

    private static final Logger logger = LoggerFactory.getLogger(F5NetworkMapServiceImpl.class);
    @Autowired
    private F5BiVirtualServerRepository f5BiVirtualServerRepository;
    @Autowired
    private F5BiPoolRepository f5BiPoolRepository;
    @Autowired
    private F5BiPoolMemberRepository f5BiPoolMemberRepository;
    @Autowired
    private F5BiIRulesRepository f5BiIRulesRepository;
    @Autowired
    private F5BiNodeRepository f5BiNodeRepository;
    @Autowired
    private F5BiPartitionRepository biPartitionRepository;
    private Map<Long, String> cachePartitionById;

    @Override
    public BocloudResult<Map<String, Object>> list(Long vendorId, JSONObject filter) {
        Map<String, Object> resultData = Maps.newHashMap();
        List<JSONObject> vsList = Lists.newArrayList();
        List<JSONObject> poolList = Lists.newArrayList();
        List<JSONObject> memberList = Lists.newArrayList();
        List<JSONObject> nodeList = Lists.newArrayList();
        int ruleTotal = 0;
        try {
            // 查出所有的分区缓存
            List<BiPartition> partitions = biPartitionRepository.list(vendorId);
            cachePartitionById = Maps.newHashMap();
            for (BiPartition biPartition : partitions) {
                cachePartitionById.put(biPartition.getId(), biPartition.getName());
            }
            // 查询当前云平台所有的vs
            List<BiVirtualServer> virtualServers = f5BiVirtualServerRepository.list(vendorId);
            Iterator<BiVirtualServer> iterator = virtualServers.iterator();
            while (iterator.hasNext()) {
                BiVirtualServer virtualServer = iterator.next();
                // 构建vs数据
                JSONObject vsMap = new JSONObject();
                vsMap.put("id", virtualServer.getId());
                vsMap.put("vsName", virtualServer.getName());
                vsMap.put("partition", cachePartitionById.get(virtualServer.getPartitionId()));
                vsMap.put("destinationAddress", virtualServer.getAddress() + ":" + virtualServer.getPort());
                vsMap.put("status", virtualServer.getStatus());
                // 获取vs关联的rule
                List<Map<String, Object>> rules = Lists.newArrayList();
                List<Long> ruleIds = JSONArray.parseArray(virtualServer.getIrules()).toJavaList(Long.class);
                for (Long ruleId : ruleIds) {
                    BiIRules biIRules = f5BiIRulesRepository.query(ruleId);
                    Map<String, Object> rule = Maps.newHashMap();
                    rule.put("id", biIRules.getId());
                    rule.put("name", biIRules.getName());
                    rule.put("partition", cachePartitionById.get(biIRules.getPartitionId()));
                    rules.add(rule);
                }
                vsMap.put("iRules", rules);
                // 获取vs关联的pool
                BiPool biPool = null;
                List<BiPoolMember> biPoolMembers = Lists.newArrayList();
                List<BiNode> nodes = Lists.newArrayList();
                Long poolId = virtualServer.getPoolId();
                if (null != poolId) {
                    biPool = f5BiPoolRepository.query(poolId);
                    JSONObject poolData = new JSONObject();
                    poolData.put("id", biPool.getId());
                    poolData.put("status", biPool.getStatus());
                    Boolean isPoolExist = true;
                    for (JSONObject pool : poolList) {
                        if (biPool.getId().equals(pool.get("id"))) {
                            isPoolExist = false;
                        }
                    }
                    if (isPoolExist) {
                        poolList.add(poolData);
                    }
                    Map<String, Object> poolMap = Maps.newHashMap();
                    poolMap.put("id", biPool.getId());
                    poolMap.put("poolName", biPool.getName());
                    poolMap.put("partition", cachePartitionById.get(biPool.getPartitionId()));
                    poolMap.put("source", "defaultPool");
                    poolMap.put("status", biPool.getStatus());
                    // 查询当前pool关联的所有member
                    biPoolMembers = f5BiPoolMemberRepository.queryByPoolId(poolId);
                    for (BiPoolMember biPoolMember : biPoolMembers) {
                        biPoolMember.setMemberName(
                                biPoolMember.getPoolMemberAddress() + ":" + biPoolMember.getPoolMemberPort());
                        BiNode biNode = f5BiNodeRepository.queryByAddress(biPoolMember.getPoolMemberAddress(), vendorId,
                                biPoolMember.getPartitionId());
                        nodes.add(biNode);
                        biPoolMember.setNodeStatus(biNode.getStatus());
                    }
                    poolMap.put("members", biPoolMembers);
                    vsMap.put("pool", poolMap);
                }
                Boolean result = entityDataSource(filter, virtualServer, rules, biPool, biPoolMembers, nodes);
                if (result) {
                    iterator.remove();
                    continue;
                } else {
                    // 为后面数量统计做准备
                    // members and node
                    for (BiPoolMember biPoolMember : biPoolMembers) {
                        JSONObject memberMap = new JSONObject();
                        memberMap.put("id", biPoolMember.getId());
                        memberMap.put("name", biPoolMember.getMemberName());
                        memberMap.put("status", biPoolMember.getStatus());
                        Boolean isMemberExist = true;
                        for (JSONObject member : memberList) {
                            if (biPoolMember.getMemberName().equals(member.get("name"))) {
                                isMemberExist = false;
                            }
                        }
                        if (isMemberExist) {
                            memberList.add(memberMap);
                        }
                        Boolean isNodeExist = true;
                        for (JSONObject node : nodeList) {
                            if (biPoolMember.getPoolMemberAddress().equals(node.get("address"))) {
                                isNodeExist = false;
                            }
                        }
                        if (isNodeExist) {
                            BiNode biNode = f5BiNodeRepository.queryByAddress(biPoolMember.getPoolMemberAddress(), vendorId,
                                    biPoolMember.getPartitionId());
                            JSONObject nodeMap = new JSONObject();
                            nodeMap.put("id", biNode.getId());
                            nodeMap.put("address", biNode.getAddress());
                            nodeMap.put("status", biNode.getStatus());
                            nodeList.add(nodeMap);
                        }
                    }
                    // irules
                    ruleTotal += ruleIds.size();
                }
                vsList.add(vsMap);
            }
            // 统计去重

            // 获取统计数据
            int virtualServersTotal = virtualServers.size();
            int poolTotal = Lists.newArrayList(poolList).size();
            int memberTotal = Lists.newArrayList(memberList).size();
            int nodeTotal = Lists.newArrayList(nodeList).size();
            Map<String, Object> vsCount = statistics(virtualServers, virtualServersTotal,
                    "virtualServers");
            Map<String, Object> poolCount = statistics(poolList, poolTotal,
                    "pools");
            Map<String, Object> memberCount = statistics(memberList, memberTotal,
                    "members");
            Map<String, Object> nodeCount = statistics(nodeList, nodeTotal,
                    "nodes");
            // irules没有状态因此只统计总数量
            Map<String, Object> ruleCount = Maps.newHashMap();
            ruleCount.put("objectType", "rules");
            ruleCount.put("total", ruleTotal);
            ruleCount.put("available", "-");
            ruleCount.put("unavailable", "-");
            ruleCount.put("offline", "-");
            ruleCount.put("unknown", "-");
            List<Map<String, Object>> summary = Lists.newArrayList();
            summary.add(vsCount);
            summary.add(poolCount);
            summary.add(memberCount);
            summary.add(nodeCount);
            summary.add(ruleCount);
            resultData.put("networkMap", vsList);
            resultData.put("summary", summary);
        } catch (Exception e) {
            logger.error("Query network map data fail:", e);
            return new BocloudResult(false, "查询失败");
        }
        return new BocloudResult(true, resultData, "查询成功");
    }

    /**
     * 根据节点状态统计数量
     *
     * @param bigIpdata
     * @param totalNumber
     * @return
     */
    private Map<String, Object> statistics(List bigIpdata, int totalNumber, String type) {
        int availableCount = 0;
        int unavailableCount = 0;
        int offlineCount = 0;
        int unknownCount = 0;
        for (Object data : bigIpdata) {
            String status;
            if ("virtualServers".equals(type)) {
                BiVirtualServer virtualServer = (BiVirtualServer) data;
                status = virtualServer.getStatus();
            } else {
                JSONObject object = (JSONObject) data;
                status = object.getString("status");
            }
            // 根据节点状态统计数量
            switch (status) {
                case "available":
                    availableCount++;
                    break;
                case "unavailable":
                    unavailableCount++;
                    break;
                case "offline":
                    offlineCount++;
                    break;
                case "unknown":
                    unknownCount++;
                    break;
                default:
                    break;
            }
        }
        Map<String, Object> statistics = Maps.newHashMap();
        statistics.put("objectType", type);
        statistics.put("total", totalNumber);
        statistics.put("available", availableCount);
        statistics.put("unavailable", unavailableCount);
        statistics.put("offline", offlineCount);
        statistics.put("unknown", unknownCount);
        return statistics;
    }

    /**
     * 过滤条件
     *
     * @param filter
     * @param biVirtualServer
     * @param rules
     * @param biPool
     * @param members
     * @return
     */
    private Boolean entityDataSource(JSONObject filter, BiVirtualServer biVirtualServer,
                                     List<Map<String, Object>> rules, BiPool biPool, List<BiPoolMember> members, List<BiNode> nodes) {
        // 获取过滤条件
        if (null == filter) {
            return true;
        }
        String search = filter.getString("search");
        String status = filter.getString("status");
        String type = filter.getString("type");
        Long partitionId = filter.getLong("partitionId");
        // 检索数据
        Boolean isResult = true;
        if (0 != partitionId) {
            if (cachePartitionById.get(partitionId).equals(cachePartitionById.get(biVirtualServer.getPartitionId()))) {
                if (null == search && null == status && null == type) {
                    return false;
                }
            } else {
                return true;
            }
        } else {
            if (null == search && null == status && null == type) {
                return false;
            }
        }
        if (null != search) {
            String vsName = biVirtualServer.getName();
            if (-1L != vsName.indexOf(search)) {
                if (null == status && null == type) {
                    return false;
                }
            }
            if (null != biPool) {
                if (-1L != biPool.getName().indexOf(search)) {
                    if (null == status && null == type) {
                        return false;
                    }
                }
            }
            for (Map<String, Object> rule : rules) {
                String ruleName = String.valueOf(rule.get("name"));
                if (-1L != ruleName.indexOf(search)) {
                    if (null == status && null == type) {
                        return false;
                    }
                }
            }
            if (null != biPool) {
                if (!isResult) {
                    for (BiPoolMember member : members) {
                        String memberName = member.getMemberName();
                        if (-1L != memberName.indexOf(search)) {
                            if (null == status && null == type) {
                                return false;
                            }
                        }
                    }
                }
            }
        }
        // 检索状态
        // 初始化状态
        if (null != status) {
            if (status.equals(biVirtualServer.getStatus())) {
                if (null == type) {
                    return false;
                }
            }
            if (null != biPool) {
                if (status.equals(biPool.getStatus())) {
                    if (null == type) {
                        return false;
                    }
                }
                for (BiPoolMember member : members) {
                    if (status.equals(member.getStatus())) {
                        if (null == type) {
                            return false;
                        }
                    }
                }
                for (BiNode node : nodes) {
                    if (status.equals(node.getStatus())) {
                        if (null == type) {
                            return false;
                        }
                    }
                }
            }
        }
        // 检索类型
        // 初始化状态
        if (null != type) {
            switch (type) {
                case "virtualServer":
                    if (null != biVirtualServer) {
                        isResult = false;
                    }
                    break;
                case "iRules":
                    if (0 < rules.size()) {
                        isResult = false;
                    }
                    break;
                case "pools":
                    if (null != biPool) {
                        isResult = false;
                    }
                    break;
                case "poolMembers":
                case "nodes":
                    if (0 < members.size()) {
                        isResult = false;
                    }
                    break;
                default:
                    break;
            }
        }
        return isResult;
    }
}
