package io.wdd.func.xray.persisit;

import io.wdd.func.xray.beans.node.ProxyNode;
import io.wdd.func.xray.beans.node.ProxyNodeType;
import io.wdd.func.xray.beans.node.XrayConfigInfo;
import io.wdd.server.beans.po.ServerInfoPO;
import io.wdd.server.coreService.CoreServerService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import static io.wdd.func.xray.persisit.cache.ProxyNodeCache.*;
import static io.wdd.rpc.init.AcceptAgentInitInfo.ALL_SERVER_CITY_INDEX;

/**
 * 为Xray Config信息 操作数据库而创建
 *  todo 初期只需要记录构建过的路径（MySQL）, 后期如此复杂的网路可以考虑上图数据库Neo4j
 */
@Service
@Slf4j
public class XrayDBOperator {

    @Resource
    CoreServerService coreServerService;


    @PostConstruct
    public void cache() {

        // 初始化就需要缓存相应的信息
        this.CacheAllProxyNodeInfo();

    }


    /**
     * 从数据库中查询到所有 代理节点的信息，并且生成 ProxyNode然后缓存至
     */
    public void CacheAllProxyNodeInfo() {

        List<ServerInfoPO> serverInfoPOList = coreServerService.serverGetAll();

        transferServerInfoToProxyNode(serverInfoPOList);

    }

    private void transferServerInfoToProxyNode(List<ServerInfoPO> serverInfoVOList) {

        // 临时内容
        int[] bitmap = new int[ALL_SERVER_CITY_INDEX.size() * 10 + 10];

        //
        int[] finalBitmap = bitmap;
        List<ProxyNode> proxyNodeList = serverInfoVOList
                .stream()
                .map(
                        serverInfoVO -> {
                            // 这里应该是 "Paripark Seoul KR" 此种异常应该手动修正
                            String serverCity = serverInfoVO
                                    .getLocation()
                                    .split(" ")[0];

                            // fix bug for Seoul的情况 tmd
                            if (!ALL_SERVER_CITY_INDEX.containsKey(serverCity)) {
                                serverCity = serverInfoVO
                                        .getLocation()
                                        .split(" ")[1];
                            }

                            int cityBitMapBase = ALL_SERVER_CITY_INDEX.get(serverCity) * 10;
                            int serverGraphNum = cityBitMapBase;
                            for (int index = cityBitMapBase; index < cityBitMapBase + 10; index++) {
                                if (finalBitmap[index] == 0) {
                                    finalBitmap[index] = 1;
                                    serverGraphNum = index;
                                    break;
                                }
                            }

                            return ProxyNode
                                    .builder()
                                    .agentTopicName(serverInfoVO.getTopicName())
                                    .num(serverGraphNum)
                                    .publicIPv4(serverInfoVO.getServerIpPbV4())
                                    .publicIPv6(serverInfoVO.getServerIpPbV6())
                                    .name(serverCity + serverGraphNum)
                                    .agentName(serverInfoVO.getServerName())
                                    .location(serverCity)
                                    .xrayConfigInfo(new XrayConfigInfo())
                                    .build();
                        }
                )
                .sorted(
                        Comparator.comparing(
                                ProxyNode::getNum
                        )
                )
                .collect(Collectors.toList());

        // 收缩邻接表的Index
        for (int realIndex = 0; realIndex < proxyNodeList.size(); realIndex++) {
            proxyNodeList
                    .get(realIndex)
                    .setNum(realIndex);
        }


        // 缓存内容
        PROXY_NODE_MAP.clear();
        PROXY_NODE_TOPIC_NAME_MAP.clear();
        PROXY_NODE_INDEX_MAP.clear();

        proxyNodeList
                .stream()
                .forEach(
                        proxyNode -> {
                            PROXY_NODE_TOPIC_NAME_MAP.put(
                                    proxyNode.getAgentTopicName(),
                                    proxyNode
                            );
                            PROXY_NODE_INDEX_MAP.put(
                                    proxyNode.getNum(),
                                    proxyNode
                            );
                            PROXY_NODE_MAP.put(
                                    proxyNode.getAgentName(),
                                    proxyNode
                            );
                        }
                );

        // 缓存订阅虚拟节点
        ProxyNode subscribeProxyNode = buildSubscribeProxyNode();
        PROXY_NODE_MAP.put(
                subscribeProxyNode.getName(),
                subscribeProxyNode
        );
        PROXY_NODE_TOPIC_NAME_MAP.put(
                subscribeProxyNode.getName(),
                subscribeProxyNode
        );

        //help gc
        bitmap = null;
        proxyNodeList = null;

    }

    private ProxyNode buildSubscribeProxyNode() {

        return ProxyNode
                .builder()
                .name(SUBSCRIBE_NODE_NAME)
                .num(0)
                .agentName("subscribe-virtual-node")
                .xrayConfigInfo(new XrayConfigInfo())
                .build();
    }

    private ProxyNodeType convertNodeType(Integer proxyType) {

        if (null == proxyType) {
            return ProxyNodeType.UNKNOWN;
        }

        switch (proxyType) {
            case 0:
                return ProxyNodeType.INTERFACE;
            case 1:
                return ProxyNodeType.RELAY;
            case 2:
                return ProxyNodeType.EXTERNAL;
            default:
                return ProxyNodeType.UNKNOWN;
        }
    }

}
