package net.vtstar.zhongtong.avi.monitoring.job;

import lombok.extern.slf4j.Slf4j;
import net.vtstar.scada.base.equipmgt.domain.*;
import net.vtstar.scada.base.equipmgt.service.EquipInfoService;
import net.vtstar.scada.base.gather.job.GatherJob;
import net.vtstar.scada.base.global.service.ModbusService;
import net.vtstar.user.mybatis.provider.Operation;
import net.vtstar.user.mybatis.provider.WhereFilter;
import net.vtstar.utils.DateUtils;
import net.vtstar.zhongtong.avi.equipment.domain.FaultRecord;
import net.vtstar.zhongtong.avi.equipment.mapper.FaultRecordMapper;
import net.wimpi.modbus.io.ModbusTCPTransaction;
import net.wimpi.modbus.msg.ModbusRequest;
import net.wimpi.modbus.msg.ModbusResponse;
import net.wimpi.modbus.msg.ReadMultipleRegistersRequest;
import net.wimpi.modbus.net.TCPMasterConnection;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/*
 *  喷涂机器人报警监听
 */
@Slf4j
@Component
public class PaintingRobotErrorJob extends GatherJob {

    private static final String EQUIPMENT_TYPE = "PAINTING_ROBOT_ERROR";

    @Autowired
    private EquipInfoService equipInfoService;
    @Autowired
    private ModbusService modbusService;

    @Autowired
    private FaultRecordMapper faultRecordMapper;

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        String startOfDay = DateUtils.parseDateToString(DateUtils.getStartOfDay(0), "yyyy-MM-dd HH:mm:ss");

        List<EquipInfo> equipInfoList = equipInfoService.getEquipInfoList(EQUIPMENT_TYPE);
        if (CollectionUtils.isEmpty(equipInfoList)) {
            return;
        }
        log.error("喷涂机器人报警监听!");
        for (EquipInfo equipInfo : equipInfoList) {
            List<EquipCommunication> commList = equipInfoService.getCommunicationListByEquipType(equipInfo.getEquipType(), 1);
            if (CollectionUtils.isEmpty(commList)) {
                return;
            }
            for (EquipCommunication communication : commList) {
                EquipDataChannel dataChannel = communication.getDataChannel();
                String ip = dataChannel.getIp();
                Integer port = dataChannel.getPort();
                Integer slaveId = dataChannel.getNo();
                EquipDataTemplate template = communication.getDataTemplate();
                if (template == null) {
                    log.error("喷涂机器人无法获取设备的数据模板，设备编号：{}", dataChannel.getEquipCode());
                    continue;
                }
                List<EquipDataTemplateItem> templateItemList = template.getTemplateItemList();
                if (CollectionUtils.isEmpty(templateItemList)) {
                    log.error("喷涂机器人无法获取数据模板的条目，设备编号：{},模板名称：{}", dataChannel.getEquipCode(), template.getName());
                    continue;
                }

                try {
                    TCPMasterConnection connection = new TCPMasterConnection(InetAddress.getByName(ip));
                    connection.setPort(port);
                    connection.setTimeout(3000);
                    connection.connect();
                    ModbusTCPTransaction transaction = new ModbusTCPTransaction(connection);
                    transaction.setReconnecting(false);
                    Map<Integer, List<EquipDataTemplateItem>> collect = templateItemList.stream().collect(Collectors.groupingBy(EquipDataTemplateItem::getAddress));
                    for (Map.Entry<Integer, List<EquipDataTemplateItem>> entry : collect.entrySet()){
                        Integer address = entry.getKey();
                        List<EquipDataTemplateItem> items = entry.getValue();
                        ModbusRequest modbusRequest = new ReadMultipleRegistersRequest(address, 1);
                        modbusRequest.setUnitID(slaveId);
                        transaction.setRequest(modbusRequest);
                        transaction.execute();
                        ModbusResponse response = transaction.getResponse();
                        if (null == response) {
                            log.error("喷涂机器人读取失败！ response 为空！SlaveId: {}, Address:{}", slaveId, address);
                            continue;
                        }
                        String[] hexStrs = response.getHexMessage().split(" ");
                        if (hexStrs.length == 9) {
                            log.error("喷涂机器人读取失败！ length 为9! SlaveId: {}, Address:{}", slaveId, address);
                            continue;
                        }
                        Byte newValue = Byte.valueOf(hexStrs[hexStrs.length - 1], 16);
                        List<Integer> values = new ArrayList<>();
                        int j = 0;
                        while (j < 8){
                            values.add((newValue >> j) & 0x01);
                            j ++;
                        }
                        log.info("newValue:{}, 读取结果:{}, 报警列表:{}", newValue, values, items);
                        items.forEach(item -> {
                            Integer value = values.get(item.getLength());
                            if (value == 1) {
                                log.error("喷涂机器人报警, 报警内容:{}", item.getFieldDesc());
                                List<FaultRecord> list = faultRecordMapper.findList(new WhereFilter() {{
                                    addFilter("begin_time", Operation.GREATER_THAN, startOfDay);
                                    addFilter("machine_code", Operation.EQUAL, "喷涂机器人02");
                                    addFilter("warning_info", Operation.EQUAL, item.getFieldDesc());
                                }}, FaultRecord.class);
                                if (CollectionUtils.isEmpty(list)) {
                                    FaultRecord faultRecord = new FaultRecord();
                                    faultRecord.setWorkshopCode("涂装车间");
                                    faultRecord.setEquipCode("喷涂机器人02");
                                    faultRecord.setBeginTime(new Date());
                                    faultRecord.setWarningInfo(item.getFieldDesc());
                                    faultRecord.setCreateTime(new Date());
                                    faultRecordMapper.insert(faultRecord);
                                } else {
                                    FaultRecord faultRecord = list.get(0);
                                    faultRecord.setEndTime(new Date());
                                    faultRecordMapper.update(faultRecord);
                                }
                            }else {
                                log.info("喷涂机器人未报警, 报警内容:{}", item.getFieldDesc());
                            }
                        });
                    }
                } catch (Exception e) {
                    log.error("读取失败。ip{}， 端口{}, slave{}", ip, port, slaveId);
                }
            }
        }
    }
}