/*
 * 文 件 名:  ChargingPileMessageHandler
 * 版    权:  华设设计集团股份有限公司
 * 描    述:  充电桩消息处理器
 * 修 改 人:  lvwenbin
 * 修改时间:  2025/12/25
 * 修改内容:
 *   1. 添加错误报文、交易记录、远程停机应答的处理
 *   2. 【新增】在channelInactive中调用ChargingDataService.onPileDisconnect更新设备离线状态
 */
package com.ruoyi.ems.charging.handler;

import com.ruoyi.ems.charging.core.ChargingPileSessionManager;
import com.ruoyi.ems.charging.model.BaseFrame;
import com.ruoyi.ems.charging.model.req.ChargingEndFrame;
import com.ruoyi.ems.charging.model.req.ChargingHandshakeFrame;
import com.ruoyi.ems.charging.model.req.ErrorReportFrame;
import com.ruoyi.ems.charging.model.req.HeartbeatReqFrame;
import com.ruoyi.ems.charging.model.req.LoginReqFrame;
import com.ruoyi.ems.charging.model.req.RealtimeDataFrame;
import com.ruoyi.ems.charging.model.req.RemoteStopRespFrame;
import com.ruoyi.ems.charging.model.req.TransactionRecordFrame;
import com.ruoyi.ems.charging.model.req.WorkParamSetRespFrame;
import com.ruoyi.ems.charging.model.resp.HeartbeatRespFrame;
import com.ruoyi.ems.charging.model.resp.LoginRespFrame;
import com.ruoyi.ems.charging.model.resp.TransactionConfirmFrame;
import com.ruoyi.ems.charging.protocol.ProtocolConstants;
import com.ruoyi.ems.charging.service.ChargingDataService;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 充电桩消息处理器
 * 处理充电桩上送的各类协议消息
 *
 * @author lvwenbin
 * @version [版本号, 2025/12/25]
 */
@Component
@ChannelHandler.Sharable
public class ChargingPileMessageHandler extends SimpleChannelInboundHandler<BaseFrame> {

    private static final Logger log = LoggerFactory.getLogger(ChargingPileMessageHandler.class);

    @Autowired
    private ChargingPileSessionManager sessionManager;

    @Autowired
    private ChargingDataService chargingDataService;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, BaseFrame frame) throws Exception {
        byte frameType = frame.getFrameType();

        switch (frameType) {
            // 登录认证 (0x01)
            case ProtocolConstants.FRAME_TYPE_LOGIN_REQ:
                handleLoginRequest(ctx, (LoginReqFrame) frame);
                break;

            // 心跳请求 (0x03)
            case ProtocolConstants.FRAME_TYPE_HEARTBEAT_REQ:
                handleHeartbeatRequest(ctx, (HeartbeatReqFrame) frame);
                break;

            // 实时监测数据 (0x13)
            case ProtocolConstants.FRAME_TYPE_REALTIME_DATA:
                handleRealtimeData(ctx, (RealtimeDataFrame) frame);
                break;

            // 充电握手 (0x15)
            case ProtocolConstants.FRAME_TYPE_CHARGING_HANDSHAKE:
                handleChargingHandshake(ctx, (ChargingHandshakeFrame) frame);
                break;

            // 充电结束 (0x19)
            case ProtocolConstants.FRAME_TYPE_CHARGING_END:
                handleChargingEnd(ctx, (ChargingEndFrame) frame);
                break;

            // 错误报文 (0x1B)
            case ProtocolConstants.FRAME_TYPE_ERROR:
                handleErrorReport(ctx, (ErrorReportFrame) frame);
                break;

            // 远程停机命令回复 (0x35)
            case ProtocolConstants.FRAME_TYPE_REMOTE_STOP_RESP:
                handleRemoteStopResp(ctx, (RemoteStopRespFrame) frame);
                break;

            // 交易记录 (0x3B)
            case ProtocolConstants.FRAME_TYPE_TRANSACTION:
                handleTransactionRecord(ctx, (TransactionRecordFrame) frame);
                break;

            // 工作参数设置应答 (0x51)
            case ProtocolConstants.FRAME_TYPE_WORK_PARAM_SET_RESP:
                handleWorkParamSetResp(ctx, (WorkParamSetRespFrame) frame);
                break;

            default:
                log.info("收到未处理的帧类型: 0x{}", String.format("%02X", frameType & 0xFF));
                break;
        }
    }

    /**
     * 处理登录认证请求 (0x01)
     */
    private void handleLoginRequest(ChannelHandlerContext ctx, LoginReqFrame req) {
        log.info("收到登录认证请求: {}", req);

        String pileCode = req.getPileCode();
        int gunCount = req.getGunCount();

        // 验证桩信息（这里简化处理，实际应查询数据库验证）
        boolean valid = validatePile(pileCode);

        // 发送登录应答
        LoginRespFrame resp;
        if (valid) {
            // 注册会话
            sessionManager.registerSession(pileCode, ctx.channel(), gunCount);
            resp = LoginRespFrame.success(pileCode, req.getSequenceNo());
            log.info("充电桩[{}]登录成功，枪数量: {}", pileCode, gunCount);
        } else {
            resp = LoginRespFrame.fail(pileCode, req.getSequenceNo());
            log.warn("充电桩[{}]登录失败，验证未通过", pileCode);
        }

        ctx.writeAndFlush(resp);

        // 通知业务层（会更新主机和子设备的在线状态）
        chargingDataService.onPileLogin(req, valid);
    }

    /**
     * 处理心跳请求 (0x03)
     */
    private void handleHeartbeatRequest(ChannelHandlerContext ctx, HeartbeatReqFrame req) {
        log.debug("收到心跳请求: {}", req);

        String pileCode = req.getPileCode();

        // 更新心跳时间
        sessionManager.updateHeartbeat(pileCode);

        // 发送心跳应答
        HeartbeatRespFrame resp = HeartbeatRespFrame.create(pileCode, req.getGunNo(), req.getSequenceNo());
        ctx.writeAndFlush(resp);

        // 如果枪状态异常，通知业务层
        if (!req.isNormal()) {
            log.warn("充电桩[{}]枪[{}]状态异常: 故障", pileCode, req.getGunNo());
            chargingDataService.onGunFault(pileCode, req.getGunNo());
        }
    }

    /**
     * 处理实时监测数据 (0x13)
     * 这是能耗平台最核心的数据处理
     */
    private void handleRealtimeData(ChannelHandlerContext ctx, RealtimeDataFrame data) {
        log.info("收到实时监测数据: {}", data);

        // 更新心跳时间
        sessionManager.updateHeartbeat(data.getPileCode());

        // 处理实时数据
        chargingDataService.processRealtimeData(data);
    }

    /**
     * 处理充电握手 (0x15)
     */
    private void handleChargingHandshake(ChannelHandlerContext ctx, ChargingHandshakeFrame handshake) {
        log.info("收到充电握手: {}", handshake);

        // 通知业务层
        chargingDataService.onChargingHandshake(handshake);
    }

    /**
     * 处理充电结束 (0x19)
     */
    private void handleChargingEnd(ChannelHandlerContext ctx, ChargingEndFrame end) {
        log.info("收到充电结束: {}", end);

        // 通知业务层
        chargingDataService.onChargingEnd(end);
    }

    /**
     * 处理错误报文 (0x1B) - 新增
     * 用于接收充电过程中的通信异常信息
     */
    private void handleErrorReport(ChannelHandlerContext ctx, ErrorReportFrame error) {
        if (error.hasError()) {
            log.warn("收到错误报文: {}", error);
        } else {
            log.debug("收到错误报文(无错误): {}", error);
        }

        // 通知业务层
        chargingDataService.onErrorReport(error);
    }

    /**
     * 处理远程停机命令回复 (0x35) - 新增
     */
    private void handleRemoteStopResp(ChannelHandlerContext ctx, RemoteStopRespFrame resp) {
        if (resp.isSuccess()) {
            log.info("远程停机成功: {}", resp);
        } else {
            log.warn("远程停机失败: {}", resp);
        }

        // 通知业务层
        chargingDataService.onRemoteStopResp(resp);
    }

    /**
     * 处理交易记录 (0x3B)
     * 这是能耗统计最重要的数据，包含分时电量
     */
    private void handleTransactionRecord(ChannelHandlerContext ctx, TransactionRecordFrame record) {
        log.info("收到交易记录: {}", record);

        // 发送确认应答
        TransactionConfirmFrame confirmFrame = TransactionConfirmFrame.success(
            record.getTransactionNo(), record.getSequenceNo());
        ctx.writeAndFlush(confirmFrame);

        log.info("已发送交易记录确认: transNo={}", record.getTransactionNo());

        // 通知业务层处理交易记录
        chargingDataService.onTransactionRecord(record);
    }

    /**
     * 处理工作参数设置应答 (0x51)
     */
    private void handleWorkParamSetResp(ChannelHandlerContext ctx, WorkParamSetRespFrame resp) {
        log.info("收到工作参数设置应答: {}", resp);

        // 通知业务层
        chargingDataService.onWorkParamSetResp(resp);
    }

    /**
     * 验证充电桩
     * 实际应用中应查询数据库验证桩信息
     */
    private boolean validatePile(String pileCode) {
        // 简单验证：桩编号不为空且长度合法
        return pileCode != null && !pileCode.isEmpty() && pileCode.length() <= 14;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        log.info("充电桩连接建立: {}", ctx.channel().remoteAddress());
        super.channelActive(ctx);
    }

    /**
     * 连接断开时的处理
     * 1. 注销会话
     * 2. 调用ChargingDataService更新设备离线状态
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        log.info("充电桩连接断开: {}", ctx.channel().remoteAddress());

        // 1. 先获取桩编码（在注销前获取，否则就拿不到了）
        String pileCode = sessionManager.getPileCodeByChannel(ctx.channel());

        // 2. 注销会话
        sessionManager.unregisterSession(ctx.channel());

        // 3. 通知业务层处理设备离线
        if (pileCode != null) {
            try {
                chargingDataService.onPileDisconnect(pileCode);
            } catch (Exception e) {
                log.error("处理充电桩断开连接时发生异常 - 桩号: {}", pileCode, e);
            }
        }

        super.channelInactive(ctx);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.error("消息处理异常: {} - {}", ctx.channel().remoteAddress(), cause.getMessage(), cause);
        ctx.close();
    }
}