package com.zehong.system.service.impl;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.List;

import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.zehong.common.utils.DateUtils;
import com.zehong.common.utils.StringUtils;
import com.zehong.system.domain.TEquipmentInfo;
import com.zehong.system.domain.TStoreyInfo;
import com.zehong.system.domain.TTrayInfo;
import com.zehong.system.mapper.TEquipmentInfoMapper;
import com.zehong.system.mapper.TStoreyInfoMapper;
import com.zehong.system.mapper.TTrayInfoMapper;
import com.zehong.system.modbus.util.Modbus4jUtils;
import com.zehong.system.netty.handler.NettyUdpServerHandler;
import com.zehong.system.service.websocket.RobotArmWebSocketHandler;
import com.zehong.system.task.CheckPowerOnCommandEvent;
import com.zehong.system.udp.UdpCommandSender;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import com.zehong.system.mapper.RobotArmCommandMapper;
import com.zehong.system.domain.RobotArmCommand;
import com.zehong.system.service.IRobotArmCommandService;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * 机械臂指令Service业务层处理
 * 
 * @author zehong
 * @date 2025-08-04
 */
@Service
public class RobotArmCommandServiceImpl implements IRobotArmCommandService 
{
    private static final Logger log = LoggerFactory.getLogger(RobotArmCommandServiceImpl.class);

    @Resource
    private NettyUdpServerHandler nettyUdpServerHandler;

    @Resource
    private RobotArmWebSocketHandler robotArmWebSocketHandler;

    @Resource
    private RobotArmCommandMapper robotArmCommandMapper;

    @Resource
    private TStoreyInfoMapper storeyInfoMapper;

    @Resource
    private TEquipmentInfoMapper equipmentInfoMapper;;

    @Resource
    private TTrayInfoMapper tTrayInfoMapper;

    @Resource
    private UdpCommandSender udpCommandSender;
    @Value("${robot.arm.udp.ip}")
    private String robotArmAddress;

    @Value("${robot.arm.udp.port}")
    private int robotArmPort;

    @Resource
    private ApplicationEventPublisher eventPublisher; // 新增事件发布器

    private SocketAddress getRobotAddress() {
        try {
            return new InetSocketAddress(
                    InetAddress.getByName(robotArmAddress), robotArmPort);
        } catch (UnknownHostException e) {
            throw new RuntimeException("无效的机械臂地址: " + robotArmAddress);
        }
    }

    @Override
    @Transactional
    public void processPendingCommands() {
        // 1. 处理待执行的上料指令
        List<RobotArmCommand> loadingCommands =
                robotArmCommandMapper.selectPendingLoadingCommands();
        if (!loadingCommands.isEmpty()) {
// 传送带检测先去掉
//            boolean[] roboticArmEntryConveyorData = Modbus4jUtils.getRoboticArmEntryConveyorData();
//            log.info("机械臂入口 conveyor 0状态: " + roboticArmEntryConveyorData[0]);
//            log.info("机械臂入口 conveyor 1状态: " + roboticArmEntryConveyorData[1]);
//            if(roboticArmEntryConveyorData[1]) {
//                sendCommand(loadingCommands.get(0), "LOAD");
//                return;
//            }
            log.info("开始处理上料指令: {}", loadingCommands.get(0));
              sendCommand(loadingCommands.get(0), "LOAD");
        }

        // 2. 处理待执行的下料指令
        List<RobotArmCommand> unloadingCommands =
                robotArmCommandMapper.selectPendingUnloadingCommands();
        if (!unloadingCommands.isEmpty()) {

//            boolean[] roboticArmExitConveyorData = Modbus4jUtils.getRoboticArmExitConveyorData();
//            if(roboticArmExitConveyorData[1]) {
                log.info("开始处理下料指令: {}", unloadingCommands.get(0));
                sendCommand(unloadingCommands.get(0), "UNLOAD");
//            }
        }
    }


    private void sendCommand(RobotArmCommand command, String commandType) {
        // 更新状态为执行中
        command.setStatus("2");
        command.setStartExecutionTime(new Date());
        robotArmCommandMapper.updateRobotArmCommand(command);

        // 如果是下料，则 先断电再去下料
        if("UNLOAD".equals(commandType)) {
            String trayCode = command.getTrayCode();
            String[] split = trayCode.split("-");

            TEquipmentInfo tEquipmentInfo = equipmentInfoMapper.selectTEquipmentInfoByCode(split[0]);

            int layer = Integer.parseInt(split[0]);

            try {
                ModbusMaster master = Modbus4jUtils.getMaster(tEquipmentInfo.getfPowerOutageIp(), tEquipmentInfo.getfPowerOutagePort());
                Modbus4jUtils.writeCoil(master, 1, layer, false);
                log.info("已发送断电指令 - 设备:{} 层:{}", tEquipmentInfo.getfEquipmentCode(), layer);
                master.destroy();
            } catch (ModbusTransportException | ModbusInitException e) {
                log.info("下料发送断电指令失败 - 设备:{} 层:{}", tEquipmentInfo.getfEquipmentCode(), layer);
                throw new RuntimeException(e);
            }
        }

        // 通过WebSocket广播更新
        robotArmWebSocketHandler.broadcastCommandUpdate();

        // 发送UDP指令
        SocketAddress address = getRobotAddress();

        udpCommandSender.sendCommandWithId(
                address,
                command.getCommand()
        );

        // 注册指令跟踪
        nettyUdpServerHandler.registerCommandExecution("127.0.0.1", command.getRobotArmCommandId());
    }

    /**
     * 发送归位指令
     */
    @Override
    public void sendHomeCommand() {
        // 发送UDP指令
        SocketAddress address = getRobotAddress();
        udpCommandSender.sendCommandWithId(
                address,
                "HOME"
        );
    }

    @Override
    public void sendStopCommand() {

        // 发送UDP指令
        SocketAddress address = getRobotAddress();
        udpCommandSender.sendCommandWithId(
                address,
                "STOP"
        );
    }

    /**
     * 发送指令
     * @param command c
     */
    @Override
    public void sendCommand(String command) {
        SocketAddress robotAddress = getRobotAddress();
        udpCommandSender.sendCommandWithId(
                robotAddress,
                command
        );
    }

    @Override
    @Transactional
    public void completeCommand(Long commandId) {
        log.info("开始处理完成指令: {}", commandId);
        RobotArmCommand command = robotArmCommandMapper.selectRobotArmCommandById(commandId);
        if (command != null && "2".equals(command.getStatus())) {

            log.info("command != null && \"2\".equals(command.getStatus()");
            // 发送上电指令
            try {
                // 上料的指令 需要去上电
                if("0".equals(command.getType())){
                    log.info("\"0\".equals(command.getType()");
                    // 发送上电指令给机械臂
                    String storeyCode = command.getStoreyCode();
                    String equitmentCode = "";
                    Integer registerOffset = null;
                    if(storeyCode.contains("-")) {
                        log.info("storeyCode.contains(\"-\")");
                        String[] parts = storeyCode.split("-");
                        equitmentCode = parts[0];
                        registerOffset = Integer.parseInt(parts[1]);
                        TEquipmentInfo tEquipmentInfo = equipmentInfoMapper.selectTEquipmentInfoByCode(equitmentCode);

                        if(tEquipmentInfo != null) {
                            log.info("tEquipmentInfo != null");
                            String powerOutageIp = tEquipmentInfo.getfPowerOutageIp();
                            Integer powerOutagePort = tEquipmentInfo.getfPowerOutagePort();
                            if(StringUtils.isNotBlank(powerOutageIp) && powerOutagePort != null) {

                                eventPublisher.publishEvent(new CheckPowerOnCommandEvent(
                                        this,
                                        equitmentCode,
                                        powerOutageIp,
                                        powerOutagePort,
                                        registerOffset,
                                        registerOffset - 1
                                ));
                            }
                        }
                    }
                // 下料的话 得解除 托盘 和 层的绑定关系
                } else {
                    TStoreyInfo tStoreyInfo = new TStoreyInfo();
                    tStoreyInfo.setfStoreyCode(command.getStoreyCode());
                    tStoreyInfo.setUpdateTime(new Date());
                    storeyInfoMapper.unbindByCode(tStoreyInfo);

                    TTrayInfo  tTrayInfo = new TTrayInfo();
                    tTrayInfo.setfTrayCode(command.getTrayCode());
                    tTrayInfo.setUpdateTime(new Date());
                    tTrayInfo.setfUnbindingTime(new Date());
                    tTrayInfoMapper.unbindByCode(tTrayInfo);
                }
                command.setStatus("4");
                log.info("指令执行成功，状态设置为4");
            } catch (Exception e) {
                command.setStatus("3");
                log.info("执行指令时发生异常: " + e.getMessage());
            }

            command.setEndExecutionTime(new Date());
            robotArmCommandMapper.updateRobotArmCommand(command);

            // 通过WebSocket广播更新
            robotArmWebSocketHandler.broadcastCommandUpdate();
        }
    }

    @Override
    @Transactional
    public void markCommandTimeout(Long commandId) {
        RobotArmCommand command = robotArmCommandMapper.selectRobotArmCommandById(commandId);
        if (command != null && "2".equals(command.getStatus())) {
            command.setStatus("5"); // 执行异常；先保留此参数
            robotArmCommandMapper.updateRobotArmCommand(command);

            // 通过WebSocket广播更新
            robotArmWebSocketHandler.broadcastCommandUpdate();

            robotArmWebSocketHandler.broadcastStatus("idle");
        }
    }

    /**
     * 查询机械臂指令
     * 
     * @param robotArmCommandId 机械臂指令ID
     * @return 机械臂指令
     */
    @Override
    public RobotArmCommand selectRobotArmCommandById(Long robotArmCommandId)
    {
        return robotArmCommandMapper.selectRobotArmCommandById(robotArmCommandId);
    }

    /**
     * 查询机械臂指令列表
     * 
     * @param robotArmCommand 机械臂指令
     * @return 机械臂指令
     */
    @Override
    public List<RobotArmCommand> selectRobotArmCommandList(RobotArmCommand robotArmCommand)
    {
        return robotArmCommandMapper.selectRobotArmCommandList(robotArmCommand);
    }

    @Override
    public List<RobotArmCommand> findByType(String type) {
        return robotArmCommandMapper.findByType( type);
    }

    /**
     * 批量新增空闲指令
     *
     * @param robotArmCommand  r
     * @return r
     */
    @Override
    public int insertBlankingRobotArmCommand(RobotArmCommand robotArmCommand) {

        if(robotArmCommand.getTrayCode() ==  null || robotArmCommand.getStoreyCode() == null) {
            throw new RuntimeException("托盘和层不能为空");
        }

        // type 1  是 待下料的
        RobotArmCommand executingCommandByType = robotArmCommandMapper.findExecutingCommandByType(robotArmCommand.getTrayCode(), robotArmCommand.getStoreyCode(), "1");
        if(executingCommandByType != null) {
            throw new RuntimeException("当前托盘正在执行指令");
        }

        TStoreyInfo tStoreyInfo = storeyInfoMapper.selectNearestFreeStorey();
        robotArmCommand.setCommand(tStoreyInfo.getBlankingCommand());
        robotArmCommand.setCreateTime(DateUtils.getNowDate());

        return robotArmCommandMapper.insertRobotArmCommand(robotArmCommand);
    }

    /**
     * 新增机械臂指令
     * 
     * @param robotArmCommand 机械臂指令
     * @return 结果
     */
    @Override
    public int insertRobotArmCommand(RobotArmCommand robotArmCommand)
    {
        robotArmCommand.setCreateTime(DateUtils.getNowDate());

        if(StringUtils.isBlank(robotArmCommand.getTrayCode())) {
            throw new RuntimeException("托盘编号不能为空");
        }

        TTrayInfo tTrayInfo = tTrayInfoMapper.selectTTrayInfoByCode(robotArmCommand.getTrayCode());

        if(tTrayInfo == null) {
            throw new RuntimeException("托盘不存在");
        }

        if(!"0".equals(tTrayInfo.getfStatus())) {
            throw new RuntimeException("托盘未解绑，请联系管理员");
        }

        TStoreyInfo tStoreyInfo = storeyInfoMapper.selectNearestFreeStorey();
        if(tStoreyInfo != null) {
            robotArmCommand.setStatus("1");
            robotArmCommand.setStoreyCode(tStoreyInfo.getfStoreyCode());
            robotArmCommand.setCommand(tStoreyInfo.getFeedingCommand());
            tTrayInfo.setfStoreyCode(tStoreyInfo.getfStoreyCode());
            tTrayInfo.setfBindingTime(new Date());
            tTrayInfoMapper.updateTTrayInfo(tTrayInfo);
        } else {
            robotArmCommand.setStoreyCode("待分配位置");
        }

        int i = robotArmCommandMapper.insertRobotArmCommand(robotArmCommand);
        notifyCommandsUpdate();
        return i;
    }

    @Override
    @Transactional
    public void powerOnCommand(Long commandId) {
        RobotArmCommand command = robotArmCommandMapper.selectRobotArmCommandById(commandId);
        if (command == null) {
            throw new RuntimeException("指令不存在");
        }

        if (!"3".equals(command.getStatus())) {
            throw new RuntimeException("只有未上电状态的指令才能执行上电操作");
        }

        // 上完电 此条指令就结束了
        command.setStatus("4");
        robotArmCommandMapper.updateRobotArmCommand(command);

        // 发送上电指令给机械臂
        String udpMessage = String.format("POWER_ON,%s,%s", command.getTrayCode(), command.getStoreyCode());
        udpCommandSender.sendCommand(udpMessage);

        // 记录操作日志
        log.info("执行上电操作: 指令ID={}, 托盘={}, 位置={}", commandId, command.getTrayCode(), command.getStoreyCode());
        notifyCommandsUpdate();
    }

    /**
     * 修改机械臂指令
     * 
     * @param robotArmCommand 机械臂指令
     * @return 结果
     */
    @Override
    public int updateRobotArmCommand(RobotArmCommand robotArmCommand)
    {
        int i = robotArmCommandMapper.updateRobotArmCommand(robotArmCommand);
        notifyCommandsUpdate();
        return i;
    }

    /**
     * 批量删除机械臂指令
     * 
     * @param robotArmCommandIds 需要删除的机械臂指令ID
     * @return 结果
     */
    @Override
    public int deleteRobotArmCommandByIds(Long[] robotArmCommandIds)
    {
        int i = robotArmCommandMapper.deleteRobotArmCommandByIds(robotArmCommandIds);
        notifyCommandsUpdate();
        return i;
    }

    /**
     * 删除机械臂指令信息
     * 
     * @param robotArmCommandId 机械臂指令ID
     * @return 结果
     */
    @Override
    public int deleteRobotArmCommandById(Long robotArmCommandId)
    {
        int i = robotArmCommandMapper.deleteRobotArmCommandById(robotArmCommandId);
        notifyCommandsUpdate();
        return i;
    }

    private void notifyCommandsUpdate() {
        robotArmWebSocketHandler.broadcastCommandUpdate();
    }
}
