package org.framework.lazy.cloud.network.heartbeat.server.netty.udp.advanced;


import com.alibaba.fastjson.JSON;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.framework.lazy.cloud.network.heartbeat.common.ChannelContext;
import org.framework.lazy.cloud.network.heartbeat.common.constant.TcpMessageType;
import org.framework.lazy.cloud.network.heartbeat.common.NettyProxyMsg;
import org.framework.lazy.cloud.network.heartbeat.common.advanced.udp.server.AbstractHandleUdpClientConnectSuccessTypeAdvanced;
import org.framework.lazy.cloud.network.heartbeat.common.utils.ChannelAttributeKeyUtils;
import org.framework.lazy.cloud.network.heartbeat.server.properties.ServerNodeProperties;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.*;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.command.lazy.netty.client.permeate.client.mapping.LazyClientPermeateClientMappingQueryListCommand;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.command.lazy.netty.client.permeate.server.mapping.LazyClientPermeateServerMappingQueryListCommand;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.command.lazy.netty.client.state.LazyNettyClientLoginCommand;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.dto.LazyClientPermeateClientMappingDTO;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.dto.LazyClientPermeateServerMappingDTO;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.domain.model.lazy.netty.client.blacklist.LazyNettyClientBlacklist;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Role;
import org.springframework.stereotype.Component;
import org.wu.framework.web.response.Result;

import java.nio.charset.StandardCharsets;
import java.util.List;


/**
 * 服务端连接成功处理
 * TCP_REPORT_CLIENT_CONNECT_SUCCESS
 */
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
@Slf4j
@Component
public class ServerHandleUdpClientConnectSuccessTypeAdvanced extends AbstractHandleUdpClientConnectSuccessTypeAdvanced<NettyProxyMsg> {

    private final LazyClientStatsChangeApplication lazyClientStatsChangeApplication;
    private final LazyNettyClientBlacklistApplication lazyNettyClientBlacklistApplication;
    private final LazyServerPermeateClientMappingApplication lazyServerPermeateClientMappingApplication;
    private final LazyClientPermeateServerMappingApplication lazyClientPermeateServerMappingApplication;
    private final LazyClientPermeateClientMappingApplication lazyClientPermeateClientMappingApplication;

    private final LazyNettyClientTokenBucketApplication lazyNettyClientTokenBucketApplication;

    private final ServerNodeProperties serverNodeProperties;

    public ServerHandleUdpClientConnectSuccessTypeAdvanced(LazyClientStatsChangeApplication lazyClientStatsChangeApplication, LazyNettyClientBlacklistApplication lazyNettyClientBlacklistApplication, LazyServerPermeateClientMappingApplication lazyServerPermeateClientMappingApplication, LazyClientPermeateServerMappingApplication lazyClientPermeateServerMappingApplication, LazyClientPermeateClientMappingApplication lazyClientPermeateClientMappingApplication, LazyNettyClientTokenBucketApplication lazyNettyClientTokenBucketApplication, ServerNodeProperties serverNodeProperties) {
        this.lazyClientStatsChangeApplication = lazyClientStatsChangeApplication;
        this.lazyNettyClientBlacklistApplication = lazyNettyClientBlacklistApplication;
        this.lazyServerPermeateClientMappingApplication = lazyServerPermeateClientMappingApplication;
        this.lazyClientPermeateServerMappingApplication = lazyClientPermeateServerMappingApplication;
        this.lazyClientPermeateClientMappingApplication = lazyClientPermeateClientMappingApplication;
        this.lazyNettyClientTokenBucketApplication = lazyNettyClientTokenBucketApplication;
        this.serverNodeProperties = serverNodeProperties;
    }


    /**
     * 处理当前数据
     *
     * @param newChannel 当前通道
     * @param msg        通道数据
     */
    @Override
    public void doHandler(Channel newChannel, NettyProxyMsg msg) {


        String clientId = msg.getClientIdString();
        String appKey = msg.getAppKeyString();
        String appSecret = msg.getAppSecretString();
        String originalIp = msg.getOriginalIpString();
        ChannelContext.push(newChannel, clientId);

        ChannelAttributeKeyUtils.buildClientId(newChannel, clientId);
        ChannelAttributeKeyUtils.buildAppKey(newChannel, appKey);
        ChannelAttributeKeyUtils.buildAppSecret(newChannel, appSecret);
        ChannelAttributeKeyUtils.buildOriginalIp(newChannel, originalIp);

        // 客户端:{}，IP:{}连接成功
        log.info("Client: {}, IP: {} Connection successful", new String(msg.getClientId()), newChannel.remoteAddress().toString());
        // 验证客户端是否时黑名单
        LazyNettyClientBlacklist lazyNettyClientBlacklist = new LazyNettyClientBlacklist();
        lazyNettyClientBlacklist.setClientId(clientId);
        lazyNettyClientBlacklist.setIsDeleted(false);
        lazyNettyClientBlacklistApplication.exists(lazyNettyClientBlacklist).accept(exists -> {
            if (!exists) {
                // 认证验证
                Result<Boolean> existsTokenResult = lazyNettyClientTokenBucketApplication.certificationToken(clientId, appKey, appSecret);
                Boolean existsToken= existsTokenResult.getData();
                Boolean enableTokenVerification = serverNodeProperties.getEnableTokenVerification();
                existsToken = enableTokenVerification ? existsToken : true;
                if(existsToken){
                    // 服务状态在线
                    LazyNettyClientLoginCommand lazyNettyClientLoginCommand = new LazyNettyClientLoginCommand();
                    lazyNettyClientLoginCommand.setClientId(clientId);
                    lazyNettyClientLoginCommand.setAppKey(appKey);
                    lazyNettyClientLoginCommand.setAppSecret(appSecret);
                    lazyNettyClientLoginCommand.setOriginalIp(originalIp);
                    lazyClientStatsChangeApplication.clientOnLine(lazyNettyClientLoginCommand);
                    // 当前在线客户端数量:{}
                    log.info("Current number of online clients: {}", ChannelContext.getClientIds().size());
                    // 所有的客户端ID
                    List<String> clientIdList = ChannelContext.getClientIds();

                    // TODO 多副本本地channel 无法共享问题
                    // 通知所有客户端有人上线了
                    ChannelContext.getChannels().forEach((existClientId, channels) -> {
                        NettyProxyMsg nettyMsg = new NettyProxyMsg();
                        nettyMsg.setType(TcpMessageType.TCP_DISTRIBUTE_CLIENT_CONNECTION_SUCCESS_NOTIFICATION);
                        nettyMsg.setData((JSON.toJSONString(clientIdList)
                                .getBytes(StandardCharsets.UTF_8)));
                        // 发送所有客户端ID
                        for (Channel channel : channels) {
                            channel.writeAndFlush(nettyMsg);
                        }
                    });
                    // 开始开启客户端：【{}】,端口映射
                    log.info("Start opening client: [{}], port mapping", clientId);
                    // 创建访问者（内网穿透连接创建）
                    lazyServerPermeateClientMappingApplication.createVisitor(clientId);
                    // 结束开启客户端：【{}】,端口映射
                    log.info("End opening client: [{}], port mapping", clientId);
                }else {
                    // 关闭通道
                    log.warn("无法认证客户端：【{}】",clientId);
                    newChannel.close();
                }


            } else {
                // 黑名单客户端

            }
        });
        // 查询客户端渗透服务端信息
        LazyClientPermeateServerMappingQueryListCommand lazyClientPermeateServerMappingQueryListCommand = new LazyClientPermeateServerMappingQueryListCommand();
        lazyClientPermeateServerMappingQueryListCommand.setClientId(clientId);
        lazyClientPermeateServerMappingQueryListCommand.setIsDeleted(false);
        lazyClientPermeateServerMappingApplication.findList(lazyClientPermeateServerMappingQueryListCommand)
                .accept(lazyInternalNetworkClientPermeateServerMappingDTOS -> {
                    for (LazyClientPermeateServerMappingDTO lazyClientPermeateServerMappingDTO : lazyInternalNetworkClientPermeateServerMappingDTOS) {

                        String permeateTargetIp = lazyClientPermeateServerMappingDTO.getPermeateTargetIp();
                        Integer permeateTargetPort = lazyClientPermeateServerMappingDTO.getPermeateTargetPort();
                        Integer visitorPort = lazyClientPermeateServerMappingDTO.getVisitorPort();
                        NettyProxyMsg nettyMsg = new NettyProxyMsg();
                        nettyMsg.setType(TcpMessageType.TCP_DISTRIBUTE_CLIENT_PERMEATE_SERVER_INIT);
                        nettyMsg.setClientTargetIp(permeateTargetIp);
                        nettyMsg.setClientTargetPort(permeateTargetPort);
                        nettyMsg.setVisitorPort(visitorPort);
                        newChannel.writeAndFlush(nettyMsg);
                    }
        });


        // 查询客户端渗透客户端信息
        LazyClientPermeateClientMappingQueryListCommand lazyClientPermeateClientMappingQueryListCommand = new LazyClientPermeateClientMappingQueryListCommand();
        lazyClientPermeateClientMappingQueryListCommand.setFromClientId(clientId);
        lazyClientPermeateClientMappingQueryListCommand.setIsDeleted(false);
        lazyClientPermeateClientMappingApplication.findList(lazyClientPermeateClientMappingQueryListCommand)
                .accept(lazyInternalNetworkClientPermeateServerMappingDTOS -> {
                    for (LazyClientPermeateClientMappingDTO lazyClientPermeateClientMappingDTO : lazyInternalNetworkClientPermeateServerMappingDTOS) {

                        String permeateTargetIp = lazyClientPermeateClientMappingDTO.getPermeateTargetIp();
                        Integer permeateTargetPort = lazyClientPermeateClientMappingDTO.getPermeateTargetPort();
                        Integer visitorPort = lazyClientPermeateClientMappingDTO.getVisitorPort();
                        String toClientId = lazyClientPermeateClientMappingDTO.getToClientId();
                        NettyProxyMsg nettyMsg = new NettyProxyMsg();
                        nettyMsg.setType(TcpMessageType.TCP_DISTRIBUTE_CLIENT_PERMEATE_CLIENT_INIT);
                        nettyMsg.setClientTargetIp(permeateTargetIp);
                        nettyMsg.setClientTargetPort(permeateTargetPort);
                        nettyMsg.setVisitorPort(visitorPort);
                        nettyMsg.setClientId(clientId);
                        nettyMsg.setData(toClientId.getBytes(StandardCharsets.UTF_8));
                        newChannel.writeAndFlush(nettyMsg);
                    }
                });

    }

}
