package org.example.background.service;

import com.ghgande.j2mod.modbus.util.ModbusUtil;
import org.example.background.dao.EnergyDataDao;
import org.example.background.entity.EnergyDataEntity;
import org.example.utils.IdService;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.nio.ByteBuffer;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * author zjb
 * 服务端发送指令给下位
 */
@Component
public class MakeInfoService {

    @Resource
    private EnergyDataDao energyDataDao;

    @Resource
    private IdService idService;

    private Lock lock = new ReentrantLock();

    //读取0001-0100的数据共100个寄存器 能量表
    public int[] sendEnergyMessage () {
        int [] data = new int[8];
        data[0] = 0x01;
        data[1] = 0x03;
        data[2] = 0x00;
        data[3] = 0x00;
        data[4] = 0x00;
        data[5] = 0x64;
        String result = Integer.toHexString(getCrc(data));
        data[6] = Integer.parseInt(result.substring(2, 4), 16);
        data[7] = Integer.parseInt(result.substring(0, 2), 16);
        return data;
    }

    //读取1529的数据共2个寄存器 获取设备编号 能量表
    public int[] sendEnergyGetDevId () {
        int [] data = new int[8];
        data[0] = 0x01;
        data[1] = 0x03;
        data[2] = 0x05;
        data[3] = 0xF9;
        data[4] = 0x00;
        data[5] = 0x01;
        String result = Integer.toHexString(getCrc(data));
        data[6] = Integer.parseInt(result.substring(2, 4), 16);
        data[7] = Integer.parseInt(result.substring(0, 2), 16);
        return data;
    }

    //读取0101-0150的数据共50个寄存器 获取设备编号 能量表
    public int[] sendEnergyGetDevId50 () {
        int [] data = new int[8];
        data[0] = 0x01;
        data[1] = 0x03;
        data[2] = 0x00;
        data[3] = 0x64;
        data[4] = 0x00;
        data[5] = 0x32;
        String result = Integer.toHexString(getCrc(data));
        data[6] = Integer.parseInt(result.substring(2, 4), 16);
        data[7] = Integer.parseInt(result.substring(0, 2), 16);
        return data;
    }


    //获取指令最后两位(CRC校验位)
    public int getCrc (int [] bytes) {
        int crc = 0xFFFF; //初始化寄存器
        int polynomial = 0xA001; // 多项式A001对应的二进制数
        for (int i = 0; i < bytes.length - 2; i++) {
            crc ^= bytes[i];
            for (int j = 0; j < 8; j++) {
                if ((crc & 0x0001) == 1) {
                    crc >>= 1;
                    crc ^= polynomial;
                } else {
                    crc >>= 1;
                }
            }
        }
        return crc;
    }

    //响应报文转明文
    public String convertPlaintext (byte [] data) {
        //校验响应的数据是否完整且正确 crc校验
        int[] ints = ModbusUtil.calculateCRC(data, 0, data.length - 2);
        if(Integer.toHexString(ints[0]).equals(Integer.toHexString(data[data.length - 2] & 0xFF)) && Integer.toHexString(ints[1]).equals(Integer.toHexString(data[data.length - 1] & 0xFF))){
            //将寄存器值转换为可读的明文
                return ModbusUtil.toHex(data);
        }else{
            return "-1";
        }
    }

    //能量表解析 解析0000-0100的响应数据共100个寄存器的数据 16进制(浮点数) 转10进制 IEEE-754标准浮点数计算方法 浮点数 3412
    public Integer convertTextToData (String param,String clientIp) {
        lock.lock();
        Integer result = 0;
        String[] data = param.split(" ");
        if(data[2].equals("C8")) {
             result = energy1_100(data, clientIp);
        }else if(data[2].equals("64")) {
            energy101_150(data,clientIp);
        }else {
            System.out.println("客户端发送的指令不符合预期");
          }
        lock.unlock();
        return result;
    }
    public Integer energy1_100(String [] data,String clientIp){
        Integer dataCount = Integer.parseInt(data[2], 16); //数据数量
        EnergyDataEntity energyDataEntity = new EnergyDataEntity();
        energyDataEntity.setEnergyId(idService.gen());
        energyDataEntity.setDeviceId(clientIp.replace(".",""));
        energyDataEntity.setInstantaneousDelivery(hexToFloat(data[5] + data[6] + data[3] + data[4])); //瞬时流量
        energyDataEntity.setInstantHeat(hexToFloat(data[9] + data[10] + data[7] + data[8]));    //瞬时热量
        energyDataEntity.setFluidVelocity(String.valueOf(hexToFloat(data[13] + data[14] + data[11] + data[12]))); //流体速度
        energyDataEntity.setFluidVelocitySound(String.valueOf(hexToFloat(data[17]+data[18]+data[15]+data[16]))); //测量流体声速
        energyDataEntity.setPositiveTotalFlow((Long.parseLong(data[21] + data[22] + data[19] + data[20],16) + hexToFloat(data[25] + data[26] + data[23] + data[24]))); //正累计流量
        energyDataEntity.setCumulativeTraffic((Long.parseLong(data[53] + data[54] + data[51] + data[52],16) + hexToFloat(data[57] + data[58] + data[55] + data[56]))); //累计流量
        energyDataEntity.setNegativeTotalFlow((hexToLongWithSigned(data[27] ,data[28] , data[29] , data[30]) + hexToFloat(data[33] + data[34] + data[31] + data[32]))); //负累计流量
        energyDataEntity.setPositiveCumulativeHeat((Long.parseLong(data[37]+data[38]+data[35]+data[36],16) + hexToFloat(data[41]+data[42]+data[39]+data[40])));   //正累计热量
        energyDataEntity.setNegativeCumulativeHeat((hexToLongWithSigned(data[43],data[44],data[45],data[46]) + hexToFloat(data[49]+data[50]+data[47]+data[48]))); //负累计热量
        energyDataEntity.setNetCumulativeHeat((Long.parseLong(data[61]+data[62]+data[59]+data[60],16) + hexToFloat(data[65]+data[66]+data[63]+data[64])));
        energyDataEntity.setSupplyWaterTemperature(hexToFloat(data[69] + data[70] + data[67] + data[68])); //供水温度
        energyDataEntity.setReturnWaterTemperature(hexToFloat(data[73] + data[74] + data[71] + data[72])); //回水温度
        energyDataEntity.setCreateTime(new Date());
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:00:00");
        try {
            energyDataEntity.setAcquisitionTime(formatter.parse(formatter.format(new Date())));
        }catch (ParseException e) {
            e.printStackTrace();
        }
        Integer insert = energyDataDao.insert(energyDataEntity);
        System.out.println("已入库");
        return insert;
    }

    public void energy101_150(String [] data, String clientIp) {
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:00:00");
        Integer dataCount = Integer.parseInt(data[2], 16); //数据数量
        EnergyDataEntity entity = new EnergyDataEntity();
        entity.setDeviceId(clientIp.replace(".",""));
        try {
            entity.setAcquisitionTime(formatter.parse(formatter.format(new Date())));
        }catch (ParseException e) {
            e.printStackTrace();
        }
        EnergyDataEntity energyDataEntity = energyDataDao.select(entity);
        energyDataEntity.setAccumulatedTrafficDay((Long.parseLong(data[77]+data[78]+data[75]+data[76],16) + hexToFloat(data[81]+data[82]+data[79]+data[80])));
        energyDataEntity.setAccumulatedTrafficMonth((Long.parseLong(data[85]+data[86]+data[83]+data[84],16) + hexToFloat(data[89]+data[90]+data[87]+data[88])));
        energyDataEntity.setAccumulatedTrafficYear((Long.parseLong(data[93]+data[94]+data[91]+data[92],16) + hexToFloat(data[97]+data[98]+data[95]+data[96])));
        energyDataDao.updateByPrimaryKey(energyDataEntity);
        System.out.println("已经填补剩余数据");
    }


    public static float hexToFloat(String hex) {
        byte[] bytes = new byte[4];
        for (int i = 0; i < 4; i++) {
            bytes[i] = (byte) Integer.parseInt(hex.substring(i * 2, i * 2 + 2), 16);
        }
        return ByteBuffer.wrap(bytes).getFloat();
    }

    //有符号型16进制转long
    public static long hexToLongWithSigned(String a1,String a2,String a3,String a4) {
        Integer [] arr = new Integer[2];
        arr[0] = Integer.parseInt(a1+a2, 16);
        arr[1] = Integer.parseInt(a3+a4, 16);
        Arrays.sort(arr);
        String hexStr = Integer.toHexString(arr[1]) + Integer.toHexString(arr[0]);
        long unsignedValue = Long.parseUnsignedLong(hexStr, 16);
        String substring = Long.toBinaryString(unsignedValue).substring(0, 1);
        if(substring.equals("0")){
            unsignedValue = 0;
        } else if(substring.equals("1")){
            unsignedValue = (long) -(Math.pow(2,32) - unsignedValue);
        }else if(substring.equals("0")){
            unsignedValue = (long) (Math.pow(2,32) - unsignedValue);
        }
        return unsignedValue;
    }
}
