package org.framework.lazy.cloud.network.heartbeat.server.netty.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.MessageType;
import org.framework.lazy.cloud.network.heartbeat.common.NettyProxyMsg;
import org.framework.lazy.cloud.network.heartbeat.common.advanced.server.AbstractHandleClientConnectSuccessTypeAdvanced;
import org.framework.lazy.cloud.network.heartbeat.common.utils.ChannelAttributeKeyUtils;
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.LazyInternalNetworkClientPermeateClientMappingQueryListCommand;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.command.lazy.netty.client.permeate.server.mapping.LazyInternalNetworkClientPermeateServerMappingQueryListCommand;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.dto.LazyInternalNetworkClientPermeateClientMappingDTO;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.dto.LazyInternalNetworkClientPermeateServerMappingDTO;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.domain.model.lazy.netty.client.blacklist.LazyNettyClientBlacklist;
import org.springframework.stereotype.Component;

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


/**
 * 服务端连接成功处理
 * REPORT_CLIENT_CONNECT_SUCCESS
 */
@Slf4j
@Component
public class ServerHandleClientConnectSuccessTypeAdvanced extends AbstractHandleClientConnectSuccessTypeAdvanced<NettyProxyMsg> {

    private final LazyClientStatsChangeApplication lazyClientStatsChangeApplication;
    private final LazyNettyClientBlacklistApplication lazyNettyClientBlacklistApplication;
    private final LazyInternalNetworkServerPermeateClientMappingApplication lazyInternalNetworkServerPermeateClientMappingApplication;
    private final LazyInternalNetworkClientPermeateServerMappingApplication lazyInternalNetworkClientPermeateServerMappingApplication;
    private final LazyInternalNetworkClientPermeateClientMappingApplication lazyInternalNetworkClientPermeateClientMappingApplication;

    public ServerHandleClientConnectSuccessTypeAdvanced(LazyClientStatsChangeApplication lazyClientStatsChangeApplication, LazyNettyClientBlacklistApplication lazyNettyClientBlacklistApplication, LazyInternalNetworkServerPermeateClientMappingApplication lazyInternalNetworkServerPermeateClientMappingApplication, LazyInternalNetworkClientPermeateServerMappingApplication lazyInternalNetworkClientPermeateServerMappingApplication, LazyInternalNetworkClientPermeateClientMappingApplication lazyInternalNetworkClientPermeateClientMappingApplication) {
        this.lazyClientStatsChangeApplication = lazyClientStatsChangeApplication;
        this.lazyNettyClientBlacklistApplication = lazyNettyClientBlacklistApplication;
        this.lazyInternalNetworkServerPermeateClientMappingApplication = lazyInternalNetworkServerPermeateClientMappingApplication;
        this.lazyInternalNetworkClientPermeateServerMappingApplication = lazyInternalNetworkClientPermeateServerMappingApplication;
        this.lazyInternalNetworkClientPermeateClientMappingApplication = lazyInternalNetworkClientPermeateClientMappingApplication;
    }


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


        String clientId = new String(msg.getClientId());
        ChannelContext.push(newChannel, clientId);

        ChannelAttributeKeyUtils.buildClientId(newChannel, clientId);
        // 客户端:{}，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) {
                // 服务状态在线
                lazyClientStatsChangeApplication.clientOnLine(clientId);
                // 当前在线客户端数量:{}
                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(MessageType.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);
                // 创建访问者（内网穿透连接创建）
                lazyInternalNetworkServerPermeateClientMappingApplication.createVisitor(clientId);
                // 结束开启客户端：【{}】,端口映射
                log.info("End opening client: [{}], port mapping", clientId);

            } else {
                // 黑名单客户端

            }
        });
        // 查询客户端渗透服务端信息
        LazyInternalNetworkClientPermeateServerMappingQueryListCommand lazyInternalNetworkClientPermeateServerMappingQueryListCommand = new LazyInternalNetworkClientPermeateServerMappingQueryListCommand();
        lazyInternalNetworkClientPermeateServerMappingQueryListCommand.setClientId(clientId);
        lazyInternalNetworkClientPermeateServerMappingQueryListCommand.setIsDeleted(false);
        lazyInternalNetworkClientPermeateServerMappingApplication.findList(lazyInternalNetworkClientPermeateServerMappingQueryListCommand)
                .accept(lazyInternalNetworkClientPermeateServerMappingDTOS -> {
                    for (LazyInternalNetworkClientPermeateServerMappingDTO lazyInternalNetworkClientPermeateServerMappingDTO : lazyInternalNetworkClientPermeateServerMappingDTOS) {

                        String permeateTargetIp = lazyInternalNetworkClientPermeateServerMappingDTO.getPermeateTargetIp();
                        Integer permeateTargetPort = lazyInternalNetworkClientPermeateServerMappingDTO.getPermeateTargetPort();
                        Integer visitorPort = lazyInternalNetworkClientPermeateServerMappingDTO.getVisitorPort();
                        NettyProxyMsg nettyMsg = new NettyProxyMsg();
                        nettyMsg.setType(MessageType.DISTRIBUTE_CLIENT_PERMEATE_SERVER_INIT);
                        nettyMsg.setClientTargetIp(permeateTargetIp);
                        nettyMsg.setClientTargetPort(permeateTargetPort);
                        nettyMsg.setVisitorPort(visitorPort);
                        newChannel.writeAndFlush(nettyMsg);
                    }
        });


        // 查询客户端渗透客户端信息
        LazyInternalNetworkClientPermeateClientMappingQueryListCommand lazyInternalNetworkClientPermeateClientMappingQueryListCommand = new LazyInternalNetworkClientPermeateClientMappingQueryListCommand();
        lazyInternalNetworkClientPermeateClientMappingQueryListCommand.setFromClientId(clientId);
        lazyInternalNetworkClientPermeateClientMappingQueryListCommand.setIsDeleted(false);
        lazyInternalNetworkClientPermeateClientMappingApplication.findList(lazyInternalNetworkClientPermeateClientMappingQueryListCommand)
                .accept(lazyInternalNetworkClientPermeateServerMappingDTOS -> {
                    for (LazyInternalNetworkClientPermeateClientMappingDTO lazyInternalNetworkClientPermeateClientMappingDTO : lazyInternalNetworkClientPermeateServerMappingDTOS) {

                        String permeateTargetIp = lazyInternalNetworkClientPermeateClientMappingDTO.getPermeateTargetIp();
                        Integer permeateTargetPort = lazyInternalNetworkClientPermeateClientMappingDTO.getPermeateTargetPort();
                        Integer visitorPort = lazyInternalNetworkClientPermeateClientMappingDTO.getVisitorPort();
                        String toClientId = lazyInternalNetworkClientPermeateClientMappingDTO.getToClientId();
                        NettyProxyMsg nettyMsg = new NettyProxyMsg();
                        nettyMsg.setType(MessageType.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);
                    }
                });

    }

}
