package org.framework.lazy.cloud.network.heartbeat.client.netty.socket;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.framework.lazy.cloud.network.heartbeat.client.config.NettyClientProperties;
import org.framework.lazy.cloud.network.heartbeat.client.netty.InternalNetworkClientPermeateClientVisitor;
import org.framework.lazy.cloud.network.heartbeat.client.netty.filter.NettyClientPermeateClientVisitorFilter;
import org.framework.lazy.cloud.network.heartbeat.common.NettyClientVisitorContext;
import org.framework.lazy.cloud.network.heartbeat.common.NettyVisitorPortContext;
import org.framework.lazy.cloud.network.heartbeat.common.adapter.ChannelFlowAdapter;
import org.framework.lazy.cloud.network.heartbeat.common.advanced.HandleChannelTypeAdvanced;
import org.framework.lazy.cloud.network.heartbeat.common.socket.PermeateVisitorSocket;

import java.util.List;

/**
 * 内网穿透 客户端渗透客户端通道
 *
 * @see NettyVisitorPortContext
 * @see NettyClientVisitorContext
 */
@Slf4j
public class NettyClientPermeateClientVisitorSocket implements PermeateVisitorSocket {
    private final EventLoopGroup bossGroup = new NioEventLoopGroup();
    private final EventLoopGroup workerGroup = new NioEventLoopGroup();
    private final NettyClientPermeateClientVisitorFilter nettyClientPermeateClientVisitorFilter;
    @Getter
    private final String clientId;
    @Getter
    private final int visitorPort;

    public NettyClientPermeateClientVisitorSocket(NettyClientPermeateClientVisitorFilter nettyClientPermeateClientVisitorFilter, String clientId, int visitorPort) {
        this.nettyClientPermeateClientVisitorFilter = nettyClientPermeateClientVisitorFilter;
        this.clientId = clientId;
        this.visitorPort = visitorPort;
    }

    /**
     * 启动客户端本地端口渗透到服务端端口
     *
     */
    @Override
    public void start()  {

        Channel visitor = NettyVisitorPortContext.getVisitorChannel(visitorPort);
        if (visitor == null) {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap
                    .group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)


                    // 设置读缓冲区为2M
                    .childOption(ChannelOption.SO_RCVBUF, 2048 * 1024)
                    // 设置写缓冲区为1M
                    .childOption(ChannelOption.SO_SNDBUF, 1024 * 1024)


                    .childOption(ChannelOption.SO_KEEPALIVE, true)
//                    .childOption(ChannelOption.TCP_NODELAY, false)
                    .childOption(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000 * 60)//连接超时时间设置为 60 秒
//                    .childOption(ChannelOption.RCVBUF_ALLOCATOR, new NettyRecvByteBufAllocator(1024 * 1024))//用于Channel分配接受Buffer的分配器 默认 AdaptiveRecvByteBufAllocator.DEFAULT
                    .childOption(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(1024 * 1024, 1024 * 1024 * 2))


                    .childHandler(nettyClientPermeateClientVisitorFilter);

            try {
                 bootstrap.bind(visitorPort).sync().addListener((ChannelFutureListener) future -> {
                    if (future.isSuccess()) {
                        // 这里时异步处理
                        log.info("客户端:[{}]访客端口:[{}] 开启", clientId, visitorPort);
                        NettyVisitorPortContext.pushVisitorChannel(visitorPort, future.channel());

                    } else {
                        log.error("客户端:[{}]访客端口:[{}]绑定失败", clientId, visitorPort);
                    }
                });
                NettyVisitorPortContext.pushVisitorSocket(visitorPort, this);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        } else {
            log.warn("客户端渗透服务端:[{}]访客端口:[{}] 重复启动", clientId, visitorPort);
        }

    }
    @Override
    public void close()  {
        if (!bossGroup.isShutdown()) {
            bossGroup.shutdownGracefully();
        }
        if (!workerGroup.isShutdown()) {
            workerGroup.shutdownGracefully();
        }
        Channel visitor = NettyVisitorPortContext.getVisitorChannel(visitorPort);
        if (visitor != null) {

            // close channel
            visitor.close();
            // remove visitor
            NettyVisitorPortContext.removeVisitorChannel(visitorPort);
            // remove client this
            NettyVisitorPortContext.removeVisitorSocket(visitorPort);
            log.warn("关闭客户端 :【{}】 访客户端口:【{}】", clientId, visitorPort);
        } else {
            log.warn("关闭访客端口失败 未找到客户端通道 客户端 :【{}】 访客户端口:【{}】", clientId, visitorPort);
        }
    }


    public static final class NettyClientPermeateClientVisitorSocketBuilder {

        /**
         * 客户端ID
         */
        private String clientId;

        /**
         * 客户端目标地址
         */
        private String clientTargetIp;

        /**
         * 客户端目标端口
         */
        private Integer clientTargetPort;


        /**
         * 访问端口
         */
        private Integer visitorPort;
        /**
         * 访客ID
         */
        private String visitorId;
 /**
         * 目标客户端ID
         */
        private String toClientId;

        /**
         * 流量适配器
         */
        private ChannelFlowAdapter channelFlowAdapter;
        /**
         * 服务端地址信息
         */
        private NettyClientProperties nettyClientProperties;

        /**
         * 处理器
         */
        private List<HandleChannelTypeAdvanced> handleChannelTypeAdvancedList;

        public static NettyClientPermeateClientVisitorSocketBuilder builder() {
            return new NettyClientPermeateClientVisitorSocketBuilder();
        }

        /**
         * 填充客户端
         *
         * @param clientId 客户端
         * @return 返回当前对象
         */
        public NettyClientPermeateClientVisitorSocketBuilder builderClientId(String clientId) {
            this.clientId = clientId;
            return this;
        }

        /**
         * 绑定客户端目标IP
         *
         * @param clientTargetIp 客户端目标IP
         * @return 当前对象
         */
        public NettyClientPermeateClientVisitorSocketBuilder builderClientTargetIp(String clientTargetIp) {
            this.clientTargetIp = clientTargetIp;
            return this;
        }

        /**
         * 绑定客户端目标端口
         *
         * @param clientTargetPort 客户端目标端口
         * @return 当前对象
         */
        public NettyClientPermeateClientVisitorSocketBuilder builderClientTargetPort(Integer clientTargetPort) {
            this.clientTargetPort = clientTargetPort;
            return this;
        }

        /**
         * 绑定访客端口
         *
         * @param visitorPort 访客端口
         * @return 当前对象
         */
        public NettyClientPermeateClientVisitorSocketBuilder builderVisitorPort(Integer visitorPort) {
            this.visitorPort = visitorPort;
            return this;
        }

        /**
         * 绑定流量适配器
         *
         * @param channelFlowAdapter 流量适配器
         * @return 当前对象
         */
        public NettyClientPermeateClientVisitorSocketBuilder builderChannelFlowAdapter(ChannelFlowAdapter channelFlowAdapter) {
            this.channelFlowAdapter = channelFlowAdapter;
            return this;
        }        /**
         * 绑定流量适配器
         *
         * @param handleChannelTypeAdvancedList 流量适配器
         * @return 当前对象
         */
        public NettyClientPermeateClientVisitorSocketBuilder builderHandleChannelTypeAdvancedList(List<HandleChannelTypeAdvanced> handleChannelTypeAdvancedList) {
            this.handleChannelTypeAdvancedList = handleChannelTypeAdvancedList;
            return this;
        }
        /**
         * 服务端地址信息
         *
         * @param nettyClientProperties 客户服务端地址配置属性
         * @return 返回当前对象
         */
        public NettyClientPermeateClientVisitorSocketBuilder builderNettyClientProperties(NettyClientProperties nettyClientProperties) {
            this.nettyClientProperties = nettyClientProperties;
            return this;
        }

        /**
         * 绑定访客ID
         *
         * @param visitorId 访客ID
         * @return 当前对象
         */
        public NettyClientPermeateClientVisitorSocketBuilder builderVisitorId(String visitorId) {
            this.visitorId = visitorId;
            return this;
        }

        /**
         * 目标客户端ID
         *
         * @param toClientId 目标客户端ID
         * @return 当前对象
         */
        public NettyClientPermeateClientVisitorSocketBuilder builderToClientId(String toClientId) {
            this.toClientId = toClientId;
            return this;
        }
        public NettyClientPermeateClientVisitorSocket build() {
            if (clientTargetIp == null) {
                throw new IllegalArgumentException("clientTargetIp must not null");
            }
            if (clientTargetPort == null) {
                throw new IllegalArgumentException("clientTargetPort must not null");
            }
            if (visitorPort == null) {
                throw new IllegalArgumentException("visitorPort must not null");
            }
            InternalNetworkClientPermeateClientVisitor internalNetworkClientPermeateClientVisitor = new InternalNetworkClientPermeateClientVisitor();

            internalNetworkClientPermeateClientVisitor.setFromClientId(nettyClientProperties.getClientId());
            internalNetworkClientPermeateClientVisitor.setToClientId(toClientId);
            internalNetworkClientPermeateClientVisitor.setTargetIp(clientTargetIp);
            internalNetworkClientPermeateClientVisitor.setTargetPort(clientTargetPort);
            internalNetworkClientPermeateClientVisitor.setVisitorPort(visitorPort);
            internalNetworkClientPermeateClientVisitor.setNettyClientProperties(nettyClientProperties);
            internalNetworkClientPermeateClientVisitor.setChannelFlowAdapter(channelFlowAdapter);
            internalNetworkClientPermeateClientVisitor.setHandleChannelTypeAdvancedList(handleChannelTypeAdvancedList);


            NettyClientPermeateClientVisitorFilter visitorFilter = new NettyClientPermeateClientVisitorFilter(internalNetworkClientPermeateClientVisitor);
            return new NettyClientPermeateClientVisitorSocket(visitorFilter, clientId, visitorPort);
        }


    }

}