package org.framework.lazy.cloud.network.heartbeat.server.standalone.application.impl;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.framework.lazy.cloud.network.heartbeat.common.NettyClientVisitorContext;
import org.framework.lazy.cloud.network.heartbeat.common.adapter.ChannelFlowAdapter;
import org.framework.lazy.cloud.network.heartbeat.server.netty.tcp.socket.NettyTcpServerPermeateClientVisitorSocket;
import org.framework.lazy.cloud.network.heartbeat.server.properties.ServerNodeProperties;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.LazyServerPermeateClientMappingApplication;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.assembler.LazyNettyServerPermeateClientMappingDTOAssembler;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.command.lazy.netty.server.permeate.client.mapping.*;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.application.dto.LazyServerPermeateClientMappingDTO;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.domain.model.lazy.netty.server.permeate.client.mapping.LazyNettyServerPermeateClientMapping;
import org.framework.lazy.cloud.network.heartbeat.server.standalone.domain.model.lazy.netty.server.permeate.client.mapping.LazyNettyServerPermeateClientMappingRepository;
import org.springframework.transaction.annotation.Transactional;
import org.wu.framework.core.utils.ObjectUtils;
import org.wu.framework.database.lazy.web.plus.stereotype.LazyApplication;
import org.wu.framework.lazy.orm.core.persistence.reverse.lazy.ddd.DefaultDDDLazyApplicationImpl;
import org.wu.framework.lazy.orm.database.lambda.domain.LazyPage;
import org.wu.framework.web.response.Result;
import org.wu.framework.web.response.ResultFactory;

import java.util.List;
import java.util.stream.Collectors;

/**
 * describe 内网穿透映射
 *
 * @author Jia wei Wu
 * @date 2023/12/29 05:21 下午
 * @see DefaultDDDLazyApplicationImpl
 **/
@Slf4j
@LazyApplication
public class LazyServerPermeateClientMappingApplicationImpl implements LazyServerPermeateClientMappingApplication {

    @Resource
    LazyNettyServerPermeateClientMappingRepository lazyNettyServerPermeateClientMappingRepository;

    @Resource
    ChannelFlowAdapter channelFlowAdapter;

    @Resource
    ServerNodeProperties serverNodeProperties;


    /**
     * describe 新增内网穿透映射
     *
     * @param lazyServerPermeateClientMappingStoryCommand 新增内网穿透映射
     * @return {@link Result<    LazyNettyServerPermeateClientMapping    >} 内网穿透映射新增后领域对象
     * @author Jia wei Wu
     * @date 2023/12/29 05:21 下午
     **/

    @Override
    public Result<LazyNettyServerPermeateClientMapping> story(LazyServerPermeateClientMappingStoryCommand lazyServerPermeateClientMappingStoryCommand) {
        LazyNettyServerPermeateClientMapping lazyNettyServerPermeateClientMapping = LazyNettyServerPermeateClientMappingDTOAssembler.INSTANCE.toInternalNetworkPenetrationMapping(lazyServerPermeateClientMappingStoryCommand);
        lazyNettyServerPermeateClientMapping.setIsDeleted(false);
        String serverId = serverNodeProperties.getNodeId();
        lazyNettyServerPermeateClientMapping.setServerId(serverId);

        String clientId = lazyNettyServerPermeateClientMapping.getClientId();
        String clientTargetIp = lazyNettyServerPermeateClientMapping.getClientTargetIp();
        Integer clientTargetPort = lazyNettyServerPermeateClientMapping.getClientTargetPort();
        Integer visitorPort = lazyNettyServerPermeateClientMapping.getVisitorPort();

        // 创建访客通道池

        this.changeSocket(clientId, clientTargetIp, clientTargetPort, visitorPort);
        return lazyNettyServerPermeateClientMappingRepository.story(lazyNettyServerPermeateClientMapping);
    }

    /**
     * describe 批量新增内网穿透映射
     *
     * @param lazyServerPermeateClientMappingStoryCommandList 批量新增内网穿透映射
     * @return {@link Result<List<   LazyNettyServerPermeateClientMapping   >>} 内网穿透映射新增后领域对象集合
     * @author Jia wei Wu
     * @date 2023/12/29 05:21 下午
     **/

    @Transactional
    @Override
    public Result<List<LazyNettyServerPermeateClientMapping>> batchStory(List<LazyServerPermeateClientMappingStoryCommand> lazyServerPermeateClientMappingStoryCommandList) {
        List<LazyNettyServerPermeateClientMapping> lazyNettyServerPermeateClientMappingList =
                lazyServerPermeateClientMappingStoryCommandList
                        .stream()
                        .map(lazyInternalNetworkPenetrationMappingStoryCommand -> {
                            LazyNettyServerPermeateClientMapping lazyNettyServerPermeateClientMapping = LazyNettyServerPermeateClientMappingDTOAssembler.INSTANCE.toInternalNetworkPenetrationMapping(lazyInternalNetworkPenetrationMappingStoryCommand);
                            String serverId = serverNodeProperties.getNodeId();
                            lazyNettyServerPermeateClientMapping.setServerId(serverId);
                            return lazyNettyServerPermeateClientMapping;
                        })
                        .collect(Collectors.toList());

        Result<List<LazyNettyServerPermeateClientMapping>> batchStory = lazyNettyServerPermeateClientMappingRepository.batchStory(lazyNettyServerPermeateClientMappingList);
        // 开启端口
        for (LazyNettyServerPermeateClientMapping lazyNettyServerPermeateClientMapping : lazyNettyServerPermeateClientMappingList) {
            String clientId = lazyNettyServerPermeateClientMapping.getClientId();
            String clientTargetIp = lazyNettyServerPermeateClientMapping.getClientTargetIp();
            Integer clientTargetPort = lazyNettyServerPermeateClientMapping.getClientTargetPort();
            Integer visitorPort = lazyNettyServerPermeateClientMapping.getVisitorPort();
            this.changeSocket(clientId, clientTargetIp, clientTargetPort, visitorPort);
        }
        return batchStory;
    }

    /**
     * describe 更新内网穿透映射
     *
     * @param lazyServerPermeateClientMappingUpdateCommand 更新内网穿透映射
     * @return {@link Result<   LazyNettyServerPermeateClientMapping   >} 内网穿透映射领域对象
     * @author Jia wei Wu
     * @date 2023/12/29 05:21 下午
     **/

    @Transactional
    @Override
    public Result<LazyNettyServerPermeateClientMapping> updateOne(LazyServerPermeateClientMappingUpdateCommand lazyServerPermeateClientMappingUpdateCommand) {
        LazyNettyServerPermeateClientMapping lazyNettyServerPermeateClientMapping = LazyNettyServerPermeateClientMappingDTOAssembler.INSTANCE.toInternalNetworkPenetrationMapping(lazyServerPermeateClientMappingUpdateCommand);
        String serverId = serverNodeProperties.getNodeId();
        lazyNettyServerPermeateClientMapping.setServerId(serverId);
        // 删除绑定数据
        Result<LazyNettyServerPermeateClientMapping> story = lazyNettyServerPermeateClientMappingRepository.story(lazyNettyServerPermeateClientMapping);
        String clientId = lazyNettyServerPermeateClientMapping.getClientId();
        String clientTargetIp = lazyNettyServerPermeateClientMapping.getClientTargetIp();
        Integer clientTargetPort = lazyNettyServerPermeateClientMapping.getClientTargetPort();
        Integer visitorPort = lazyNettyServerPermeateClientMapping.getVisitorPort();
        this.changeSocket(clientId, clientTargetIp, clientTargetPort, visitorPort);
        return story;
    }


    /**
     * 变更 网络穿透
     *
     * @param clientId         客户端ID
     * @param clientTargetIp   客户端目标IP
     * @param clientTargetPort 客户端莫表端口
     * @param visitorPort      访客端口
     */
    private void changeSocket(String clientId, String clientTargetIp, Integer clientTargetPort, Integer visitorPort) {
        // 删除 客户端映射
        this.changeCloseSocket(clientId, visitorPort);
        // 更新 客户端映射
        createVisitor(clientId, clientTargetIp, clientTargetPort, visitorPort);
    }


    /**
     * 删除 通道
     *
     * @param clientId    客户端ID
     * @param visitorPort 访客端口
     */
    private void changeCloseSocket(String clientId, Integer visitorPort) {
        // 删除 客户端映射
        List<NettyTcpServerPermeateClientVisitorSocket> nettyTcpServerPermeateClientVisitorSocketList = NettyClientVisitorContext.getVisitorSockets(clientId);
        if (!ObjectUtils.isEmpty(nettyTcpServerPermeateClientVisitorSocketList)) {
            nettyTcpServerPermeateClientVisitorSocketList = nettyTcpServerPermeateClientVisitorSocketList.stream()
                    .filter(nettyTcpServerPermeateClientVisitorSocket -> nettyTcpServerPermeateClientVisitorSocket.getVisitorPort() == visitorPort).toList();
            if (!ObjectUtils.isEmpty(nettyTcpServerPermeateClientVisitorSocketList)) {
                // 关闭端口
                for (NettyTcpServerPermeateClientVisitorSocket nettyTcpServerPermeateClientVisitorSocket : nettyTcpServerPermeateClientVisitorSocketList) {
                        nettyTcpServerPermeateClientVisitorSocket.close();
                }
                // 关闭通道 socket

            }
        }
    }

    /**
     * describe 查询单个内网穿透映射
     *
     * @param lazyServerPermeateClientMappingQueryOneCommand 查询单个内网穿透映射
     * @return {@link Result<   LazyServerPermeateClientMappingDTO   >} 内网穿透映射DTO对象
     * @author Jia wei Wu
     * @date 2023/12/29 05:21 下午
     **/
    @Override
    public Result<LazyServerPermeateClientMappingDTO> findOne(LazyServerPermeateClientMappingQueryOneCommand lazyServerPermeateClientMappingQueryOneCommand) {
        LazyNettyServerPermeateClientMapping lazyNettyServerPermeateClientMapping = LazyNettyServerPermeateClientMappingDTOAssembler.INSTANCE.toInternalNetworkPenetrationMapping(lazyServerPermeateClientMappingQueryOneCommand);
        String serverId = serverNodeProperties.getNodeId();
        lazyNettyServerPermeateClientMapping.setServerId(serverId);
        return lazyNettyServerPermeateClientMappingRepository.findOne(lazyNettyServerPermeateClientMapping).convert(LazyNettyServerPermeateClientMappingDTOAssembler.INSTANCE::fromInternalNetworkPenetrationMapping);
    }

    /**
     * describe 查询多个内网穿透映射
     *
     * @param lazyServerPermeateClientMappingQueryListCommand 查询多个内网穿透映射
     * @return {@link Result<List<  LazyServerPermeateClientMappingDTO  >>} 内网穿透映射DTO对象
     * @author Jia wei Wu
     * @date 2023/12/29 05:21 下午
     **/

    @Override
    public Result<List<LazyServerPermeateClientMappingDTO>> findList(LazyServerPermeateClientMappingQueryListCommand lazyServerPermeateClientMappingQueryListCommand) {
        LazyNettyServerPermeateClientMapping lazyNettyServerPermeateClientMapping = LazyNettyServerPermeateClientMappingDTOAssembler.INSTANCE.toInternalNetworkPenetrationMapping(lazyServerPermeateClientMappingQueryListCommand);

        String serverId = serverNodeProperties.getNodeId();
        lazyNettyServerPermeateClientMapping.setServerId(serverId);
        return lazyNettyServerPermeateClientMappingRepository.findList(lazyNettyServerPermeateClientMapping).convert(internalNetworkPenetrationMappings -> internalNetworkPenetrationMappings.stream().map(LazyNettyServerPermeateClientMappingDTOAssembler.INSTANCE::fromInternalNetworkPenetrationMapping).collect(Collectors.toList()));
    }

    /**
     * describe 分页查询多个内网穿透映射
     *
     * @param lazyServerPermeateClientMappingQueryListCommand 分页查询多个内网穿透映射
     * @return {@link Result<LazyPage<  LazyServerPermeateClientMappingDTO  >>} 分页内网穿透映射DTO对象
     * @author Jia wei Wu
     * @date 2023/12/29 05:21 下午
     **/

    @Override
    public Result<LazyPage<LazyServerPermeateClientMappingDTO>> findPage(int size, int current, LazyServerPermeateClientMappingQueryListCommand lazyServerPermeateClientMappingQueryListCommand) {
        LazyNettyServerPermeateClientMapping lazyNettyServerPermeateClientMapping = LazyNettyServerPermeateClientMappingDTOAssembler.INSTANCE.toInternalNetworkPenetrationMapping(lazyServerPermeateClientMappingQueryListCommand);
        String serverId = serverNodeProperties.getNodeId();
        lazyNettyServerPermeateClientMapping.setServerId(serverId);
        return lazyNettyServerPermeateClientMappingRepository.findPage(size, current, lazyNettyServerPermeateClientMapping).convert(page -> page.convert(LazyNettyServerPermeateClientMappingDTOAssembler.INSTANCE::fromInternalNetworkPenetrationMapping));
    }

    /**
     * describe 删除内网穿透映射
     *
     * @param lazyServerPermeateClientMappingRemoveCommand 删除内网穿透映射
     * @return {@link Result<   LazyNettyServerPermeateClientMapping   >} 内网穿透映射
     * @author Jia wei Wu
     * @date 2023/12/29 05:21 下午
     **/

    @Transactional
    @Override
    public Result<LazyNettyServerPermeateClientMapping> remove(LazyServerPermeateClientMappingRemoveCommand lazyServerPermeateClientMappingRemoveCommand) {
        LazyNettyServerPermeateClientMapping lazyNettyServerPermeateClientMapping = LazyNettyServerPermeateClientMappingDTOAssembler.INSTANCE.toInternalNetworkPenetrationMapping(lazyServerPermeateClientMappingRemoveCommand);
        String serverId = serverNodeProperties.getNodeId();
        lazyNettyServerPermeateClientMapping.setServerId(serverId);
        Result<LazyNettyServerPermeateClientMapping> remove = lazyNettyServerPermeateClientMappingRepository.remove(lazyNettyServerPermeateClientMapping);
        // 删除端口映射
        String clientId = lazyServerPermeateClientMappingRemoveCommand.getClientId();
        Integer visitorPort = lazyServerPermeateClientMappingRemoveCommand.getVisitorPort();
        this.changeCloseSocket(clientId, visitorPort);
        return remove;
    }

    /**
     * 创建客户端的访问者
     *
     * @param clientId 客户端ID
     */
    @Override
    public Result<Void> createVisitor(String clientId) {
        // 查询代理信息
        LazyNettyServerPermeateClientMapping lazyNettyServerPermeateClientMapping = new LazyNettyServerPermeateClientMapping();
        lazyNettyServerPermeateClientMapping.setIsDeleted(false);
        lazyNettyServerPermeateClientMapping.setClientId(clientId);
        return lazyNettyServerPermeateClientMappingRepository
                .findList(lazyNettyServerPermeateClientMapping)
                .applyOther(internalNetworkPenetrationMappings -> {
                    for (LazyNettyServerPermeateClientMapping networkPenetrationMapping : internalNetworkPenetrationMappings) {
                        Integer visitorPort = networkPenetrationMapping.getVisitorPort();
                        String clientTargetIp = networkPenetrationMapping.getClientTargetIp();
                        Integer clientTargetPort = networkPenetrationMapping.getClientTargetPort();
                        this.createVisitor(clientId, clientTargetIp, clientTargetPort, visitorPort);
                    }
                    return ResultFactory.successOf();
                });
    }

    /**
     * 创建访客
     *
     * @param clientId         客户端ID
     * @param clientTargetIp   客户端目标IP
     * @param clientTargetPort 客户端目标端口
     * @param visitorPort      访客端口
     */
    private void createVisitor(String clientId, String clientTargetIp, Integer clientTargetPort, Integer visitorPort) {


        try {
            // 更新 客户端映射
            NettyTcpServerPermeateClientVisitorSocket nettyTcpServerPermeateClientVisitorSocket = NettyTcpServerPermeateClientVisitorSocket.NettyVisitorSocketBuilder
                    .builder()
                    .builderClientId(clientId)
                    .builderClientTargetIp(clientTargetIp)
                    .builderClientTargetPort(clientTargetPort)
                    .builderVisitorPort(visitorPort)
                    .builderChannelFlowAdapter(channelFlowAdapter)
                    .build();
            nettyTcpServerPermeateClientVisitorSocket.start();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("客户端:{},网络端口:{},开放失败", clientId, visitorPort);
            throw new RuntimeException(e);
        }
    }
}