package com.zehong.framework.netty.handler;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.concurrent.locks.ReentrantLock;

import java.io.*;
import java.util.Date;
/**
 * @author lenovo
 * @date 2025/7/31
 * @description TODO
 */
@Component
@Sharable
public class NettyUdpServerHandler extends SimpleChannelInboundHandler<DatagramPacket> {
    private static final Logger log = LoggerFactory.getLogger(NettyUdpServerHandler.class);

    // 日志文件保存目录
    // 写法1：使用双反斜杠
    private static final String LOG_DIR = "D:\\BaiduNetdiskDownload\\udp_message_logs\\";
    // 日期格式器，用于生成文件名和日志时间
    private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyyMMdd");
    private static final SimpleDateFormat TIME_FORMATTER = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    // 线程安全锁，确保文件写入安全
    private final ReentrantLock fileLock = new ReentrantLock();

    /**
     * 接收UDP消息
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
        try {
            // 获取消息内容的字节缓冲区
            ByteBuf content = packet.content();

            // 分配与消息内容长度相同的字节数组
            byte[] bytes = new byte[content.readableBytes()];

            // 将缓冲区内容复制到字节数组
            content.readBytes(bytes);

            // 尝试多种编码方式解码，用于排查问题
            String messageGbk = new String(bytes, "GBK");

            // 日志打印多种编码结果，帮助确定发送端使用的编码
            log.info("收到来自{}的UDP消息：", packet.sender());
            log.info("GBK解码: {}", messageGbk);

            // 根据实际情况选择正确的编码方式
            // 这里假设通过日志观察后确定发送端使用GBK编码
            String correctMessage = messageGbk; // 初始值，根据实际情况修改

            // 检测哪种编码更可能是正确的（简单判断）
            if (containsValidChinese(messageGbk)) {
                correctMessage = messageGbk;
            }

            // 保存消息到文件
            saveMessageToFile(packet.sender().toString(), correctMessage);

            // 处理消息逻辑
            String response = "服务器已收到UDP消息：" + correctMessage;

            // 回复客户端，明确使用UTF-8编码
            byte[] responseBytes = response.getBytes(StandardCharsets.UTF_8);
            ctx.writeAndFlush(new DatagramPacket(
                    io.netty.buffer.Unpooled.copiedBuffer(responseBytes),
                    packet.sender()));
        } catch (Exception e) {
            log.error("处理UDP消息异常", e);
        }
    }


    /**
     * 将消息保存到本地文件
     *
     * @param clientAddress 客户端地址
     * @param message       消息内容
     */
    private void saveMessageToFile(String clientAddress, String message) {
        // 创建日志目录（如果不存在）
        File dir = new File(LOG_DIR);
        if (!dir.exists()) {
            dir.mkdirs();
        }

        // 按日期生成文件名，每天一个文件
        String fileName = LOG_DIR + "udp_log_" + DATE_FORMATTER.format(new Date()) + ".log";
        // 构建日志内容
        String logContent = String.format("[%s] 客户端[%s]：%s%n",
                TIME_FORMATTER.format(new Date()),
                clientAddress,
                message);

        // 使用锁确保多线程写入安全
        fileLock.lock();
        BufferedWriter writer = null;
        try {
            // 以追加模式写入文件
            writer = new BufferedWriter(new OutputStreamWriter(
                    new FileOutputStream(fileName, true),
                    StandardCharsets.UTF_8));
            writer.write(logContent);
            writer.flush();
        } catch (IOException e) {
            log.error("保存UDP消息到文件失败", e);
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    log.error("关闭文件写入流失败", e);
                }
            }
            fileLock.unlock();
        }
    }

    /**
     * 简单判断字符串是否包含有效的中文字符
     */
    private boolean containsValidChinese(String str) {
        if (str == null || str.isEmpty()) {
            return false;
        }
        for (char c : str.toCharArray()) {
            // 中文字符的Unicode范围
            if (c >= 0x4E00 && c <= 0x9FA5) {
                return true;
            }
        }
        return false;
    }

    /**
     * 异常处理
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("UDP通道异常：{}", cause.getMessage(), cause);
        // UDP无连接，通常不需要关闭通道
    }

    /**
     * 心跳检测
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.ALL_IDLE) {
                log.info("UDP服务器超过规定时间未收到数据");
                // UDP无连接，一般不关闭通道
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
}
