package com.tongran.rocketmq.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.tongran.common.core.enums.MsgEnum;
import com.tongran.common.core.utils.DateUtils;
import com.tongran.rocketmq.domain.DeviceMessage;
import com.tongran.rocketmq.domain.RmFrpcConfigManage;
import com.tongran.rocketmq.domain.RmFrpcPortMapping;
import com.tongran.rocketmq.domain.RmNetworkInterface;
import com.tongran.rocketmq.domain.vo.FrpMsgVo;
import com.tongran.rocketmq.domain.vo.PolicyTypeVo;
import com.tongran.rocketmq.mapper.RmFrpcConfigManageMapper;
import com.tongran.rocketmq.mapper.RmFrpcPortMappingMapper;
import com.tongran.rocketmq.model.ProducerMode;
import com.tongran.rocketmq.producer.MessageProducer;
import com.tongran.rocketmq.service.IRmFrpcConfigManageService;
import com.tongran.rocketmq.service.IRmNetworkInterfaceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * FRPC配置管理Service业务层处理
 * 
 * @author tongran
 * @date 2025-12-19
 */
@Service
public class RmFrpcConfigManageServiceImpl implements IRmFrpcConfigManageService 
{
    // Redis key定义
    private static final String USED_PORTS_KEY = "frpc:used_ports";

    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private RmFrpcConfigManageMapper rmFrpcConfigManageMapper;
    @Autowired
    private RmFrpcPortMappingMapper rmFrpcPortMappingMapper;
    @Autowired
    private IRmNetworkInterfaceService rmNetworkInterfaceService;
    @Autowired
    private ProducerMode producerMode;

    /**
     * 查询FRPC配置管理
     * 
     * @param id FRPC配置管理主键
     * @return FRPC配置管理
     */
    @Override
    public RmFrpcConfigManage selectRmFrpcConfigManageById(Long id)
    {
        RmFrpcConfigManage rmFrpcConfigManage = rmFrpcConfigManageMapper.selectRmFrpcConfigManageById(id);
        setNetWorkMsg(rmFrpcConfigManage);
        return rmFrpcConfigManage;
    }

    /**
     * 查询FRPC配置管理列表
     * 
     * @param rmFrpcConfigManage FRPC配置管理
     * @return FRPC配置管理
     */
    @Override
    public List<RmFrpcConfigManage> selectRmFrpcConfigManageList(RmFrpcConfigManage rmFrpcConfigManage)
    {
        List<RmFrpcConfigManage> list = rmFrpcConfigManageMapper.selectRmFrpcConfigManageList(rmFrpcConfigManage);
        if(list != null){
            for (RmFrpcConfigManage configManage : list) {
                // 设置管理网信息
                setNetWorkMsg(configManage);
            }
        }
        return list;
    }
    /**
     * 网卡信息赋值
     * @param frpcConfigManage
     */
    public void setNetWorkMsg(RmFrpcConfigManage frpcConfigManage) {
        String clientId = frpcConfigManage.getClientId();
        // 根据clientId查询网卡信息
        RmNetworkInterface queryParam = new RmNetworkInterface();
        queryParam.setClientId(clientId);
        queryParam.setNewFlag(1);
        // 获取网络接口列表
        List<RmNetworkInterface> networkList = rmNetworkInterfaceService.selectRmNetworkInterfaceList(queryParam);

        if (networkList == null || networkList.isEmpty()) {
            return;
        }

        for (RmNetworkInterface network : networkList) {
            if ("2".equals(network.getBindIp())  || "3".equals(network.getBindIp())) {
                // 管理网IP处理
                frpcConfigManage.setMgmtPublicIp(network.getPublicIp());
                frpcConfigManage.setMgmtInterfaceName(network.getInterfaceName());
                frpcConfigManage.setMgmtMacAddress(network.getMacAddress());
                frpcConfigManage.setMgmtInterfaceType(network.getInterfaceType());
                frpcConfigManage.setMgmtIpv4Address(network.getIpv4Address());
                frpcConfigManage.setMgmtGateway(network.getGateway());
            }
        }
    }

    /**
     * 新增FRPC配置管理
     * 
     * @param rmFrpcConfigManage FRPC配置管理
     * @return 结果
     */
    @Override
    public int insertRmFrpcConfigManage(RmFrpcConfigManage rmFrpcConfigManage)
    {
        int rows = rmFrpcConfigManageMapper.insertRmFrpcConfigManage(rmFrpcConfigManage);
        return 1;
    }

    /**
     * 修改FRPC配置管理
     * 
     * @param rmFrpcConfigManage FRPC配置管理
     * @return 结果
     */
    @Override
    public int updateRmFrpcConfigManage(RmFrpcConfigManage rmFrpcConfigManage)
    {
        rmFrpcConfigManage.setUpdateTime(DateUtils.getNowDate());
        return rmFrpcConfigManageMapper.updateRmFrpcConfigManage(rmFrpcConfigManage);
    }

    /**
     * 批量删除FRPC配置管理
     * 
     * @param ids 需要删除的FRPC配置管理主键
     * @return 结果
     */
    @Override
    public int deleteRmFrpcConfigManageByIds(Long[] ids)
    {
        return rmFrpcConfigManageMapper.deleteRmFrpcConfigManageByIds(ids);
    }

    /**
     * 删除FRPC配置管理信息
     * 
     * @param id FRPC配置管理主键
     * @return 结果
     */
    @Override
    public int deleteRmFrpcConfigManageById(Long id)
    {
        return rmFrpcConfigManageMapper.deleteRmFrpcConfigManageById(id);
    }

    @Override
    public int addFrpConnect(RmFrpcConfigManage rmFrpcConfigManage) {
        rmFrpcConfigManage.setFrpcConnectionStatus(1L);
        int rows = rmFrpcConfigManageMapper.insertRmFrpcConfigManage(rmFrpcConfigManage);
        // 查询frps配置
        List<RmFrpcPortMapping> portMappingList = rmFrpcPortMappingMapper.selectRmFrpcPortMappingList(new RmFrpcPortMapping());
        Integer startRemotePort = null;
        Integer endRemotePort = null;
        String serverPort = null;
        String serverAddr = null;
        if(portMappingList != null && !portMappingList.isEmpty()){
            RmFrpcPortMapping portMapping =  portMappingList.get(0);
            startRemotePort = portMapping.getStartRemotePort();
            endRemotePort = portMapping.getEndRemotePort();
            serverPort = portMapping.getServerPort();
            serverAddr = portMapping.getServerAddr();
        }
        if(startRemotePort == null || endRemotePort == null){
            throw new RuntimeException("请先设置FRPS端口范围");
        }
        String clientId = rmFrpcConfigManage.getClientId();
        if(rmFrpcConfigManage.getFrpcRemotePort() != null){
            // 此端口被占用存储到redis，再次随机可用端口
            addUsedPort(Integer.parseInt(rmFrpcConfigManage.getFrpcRemotePort()));
        }
        // 获取一个可用的随机端口
        int availablePort = getRandomAvailablePort(clientId, startRemotePort, endRemotePort);

        if (availablePort != -1) {
            // 将端口标记为已使用
            if (addUsedPort(availablePort)) {
                // 构建端口下发信息
                FrpMsgVo frpMsgVo = new FrpMsgVo();
                frpMsgVo.setServerPort(serverPort);
                frpMsgVo.setServerAddr(serverAddr);
                frpMsgVo.setRemotePort(availablePort);
                String frpMsgStr = JSONObject.toJSONString(frpMsgVo);
                PolicyTypeVo policyTypeVo = new PolicyTypeVo();
                policyTypeVo.setFrpMsg(frpMsgStr);
                MessageProducer messageProducer = new MessageProducer();
                String configJson = JSONObject.toJSONString(policyTypeVo);
                DeviceMessage message = new DeviceMessage();
                message.setClientId(clientId);
                message.setData(configJson);
                message.setDataType(MsgEnum.获取最新策略应答.getValue());

                messageProducer.sendAsyncProducerMessage(
                        producerMode.getAgentTopic(),
                        "",
                        "",
                        JSONObject.toJSONString(message)
                );
            }
            return 1;
        }else{
            throw new RuntimeException("该端口范围内无可用端口：" + startRemotePort + "~" + endRemotePort);
        }
    }

    @Override
    public RmFrpcConfigManage getFrpMsgByClientId(RmFrpcConfigManage rmFrpcConfigManage) {
        List<RmFrpcConfigManage> list = rmFrpcConfigManageMapper.selectRmFrpcConfigManageList(rmFrpcConfigManage);
        if(list != null && !list.isEmpty()){
            return list.get(0);
        }
        return new RmFrpcConfigManage();
    }

    /**
     * 获取下一个可用的随机端口
     */
    public int getRandomAvailablePort(int startPort, int endPort) {
        validatePortRange(startPort, endPort);

        // 获取已使用的端口集合
        Set<String> usedPorts = redisTemplate.opsForSet().members(USED_PORTS_KEY);
        if (usedPorts == null) {
            usedPorts = new HashSet<>();
        }

        // 创建所有端口的列表
        List<Integer> allPorts = new ArrayList<>();
        for (int i = startPort; i <= endPort; i++) {
            allPorts.add(i);
        }

        // 随机打乱
        Collections.shuffle(allPorts);

        // 查找第一个未在Redis中存储的端口
        for (int port : allPorts) {
            if (!usedPorts.contains(String.valueOf(port))) {
                return port;
            }
        }

        return -1; // 没有可用端口
    }
    public int getRandomAvailablePort(String clientId, int startPort, int endPort) {
        // 1. 先清理这个客户端可能存在的旧端口
        cleanupClientOldPorts(clientId);

        // 2. 获取新端口
        int newPort = getRandomAvailablePort(startPort, endPort);

        // 3. 记录客户端与端口的关联
        if (newPort != -1) {
            redisTemplate.opsForHash().put(
                    "client:port:mapping",
                    clientId,
                    String.valueOf(newPort)
            );
        }

        return newPort;
    }

    /**
     * 清理客户端旧端口
     */
    private void cleanupClientOldPorts(String clientId) {
        Object oldPortObj = redisTemplate.opsForHash().get("client:port:mapping", clientId);
        if (oldPortObj != null) {
            int oldPort = Integer.parseInt(oldPortObj.toString());
            removeUsedPort(oldPort);
        }
    }

    /**
     * 判断端口是否可用（只检查Redis中是否存在）
     */
    public boolean isPortAvailable(int port) {
        // 检查Redis中是否已使用
        Boolean isUsed = redisTemplate.opsForSet().isMember(USED_PORTS_KEY, String.valueOf(port));
        return !Boolean.TRUE.equals(isUsed);
    }

    /**
     * 添加端口到已用集合
     */
    public boolean addUsedPort(int port) {
        Long result = redisTemplate.opsForSet().add(USED_PORTS_KEY, String.valueOf(port));
        return result != null && result > 0;
    }

    /**
     * 从已用集合中移除端口
     */
    public boolean removeUsedPort(int port) {
        Long result = redisTemplate.opsForSet().remove(USED_PORTS_KEY, String.valueOf(port));
        return result != null && result > 0;
    }

    /**
     * 验证端口范围参数
     */
    private void validatePortRange(int startPort, int endPort) {
        if (startPort < 1 || startPort > 65535) {
            throw new IllegalArgumentException("起始端口必须在1-65535之间");
        }
        if (endPort < 1 || endPort > 65535) {
            throw new IllegalArgumentException("结束端口必须在1-65535之间");
        }
        if (startPort > endPort) {
            throw new IllegalArgumentException("起始端口不能大于结束端口");
        }
    }
}
