package com.gyee.dataadapter.config;

import com.gyee.dataadapter.entity.PointInfo;
import lombok.Data;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 数据转换工具
 */
@Data
public class DataConverterManager {
    /**
     * 序号
     */
    private int index = 0;
    private byte[] datas;
    /**
     * 版本号
     */
    private String version = "";
    /**
     * 点位数量
     */
    private int pointCount = 0;
    /**
     * 压缩算法
     */
    private byte zipType;

    private List<PointInfo> pintInfos = new ArrayList<>();

    public DataConverterManager(byte[] bs) {
        datas = bs;

        // 初始化
        init();

    }

    private void init() {
        // 消息头，版本号数量
        version = getString(4);
        // 点位数量
        pointCount = getInt();

        zipType = getByte();

        initPoint();
    }

    /**
     * 初始化内容
     */
    private void initPoint() {
        while (index < datas.length) {
            PointInfo pi = getPointInfo();
            pintInfos.add(pi);
        }
    }

    private PointInfo getPointInfo() {
        PointInfo pi = new PointInfo();
        // 数据源
        byte source = getByte();
        pi.setSource(source);
        // 点名长度
        int pnameLen = getUshort();
        String pname = getString(pnameLen);
        pi.setPath(pname);
        // 值类型
        byte vtype = getByte();
        pi.setValueType(vtype);
        int vlen = 0;
        if (vtype == 0 || vtype == 254) {
            // 值长度
            vlen = getUshort();
        }
        // 获取的实际值
        Object val = getValueByType(vtype, vlen);
        pi.setValue(val);
        // 时间戳
        //        long ts = getLong();
        //        pi.setTime(ts);
        //时间戳转为时间
        String dateTime = getDateTime();
        pi.setTime(dateTime);
        // 状态码
        int status = getInt();
        // 质量位
        byte q = getByte();
        pi.setQuality(q);
        return pi;
    }

    /**
     * 获取实际值
     *
     * @param vtype 值类型
     * @param vlen  值长度
     * @return 实际值
     */
    private Object getValueByType(byte vtype, int vlen) {
        Object val = null;
        switch (vtype) {
            case 0:
                val = getString(vlen);
                break;
            case 1:
                val = getBool();
                break;
            case 2:
                val = getUshort();
                break;
            case 3:
                val = getInt();
                break;
            case 4:
                val = getLong();
                break;
            case 5:
                val = getFloat();
                break;
            case 6:
                val = getDouble();
                break;
            case 7:
                val = getString(vlen);
                break;
            case 8:
                val = getUshort();
                break;
            case 9:
                val = getInt();
                break;
            case 10:
                val = getLong();
                break;
            case 11:
                val = getString(vlen);
                break;
        }
        return val;
    }

    private double getDouble() {
        int count = 8;
        byte[] bs = Arrays.copyOfRange(datas, index, count + index);
        toReverserBytes(bs);
        float val = ByteBuffer.wrap(bs).getFloat();
        index += count;

        return val;
    }

    private float getFloat() {
        int count = 4;
        byte[] bs = Arrays.copyOfRange(datas, index, count + index);
        toReverserBytes(bs);
        float val = ByteBuffer.wrap(bs).getFloat();

        index += count;

        return val;
    }

    private long getLong() {
        int count = 8;
        byte[] bs = Arrays.copyOfRange(datas, index, count + index);
        toReverserBytes(bs);
        long val = ByteBuffer.wrap(bs).getLong();
        val /= 10000;

        index += count;
        return val;
    }

    private String getDateTime() {
        int count = 8;
        byte[] bs = Arrays.copyOfRange(datas, index, count + index);
        toReverserBytes(bs);
        long val = ByteBuffer.wrap(bs).getLong();
        val /= 10000;

        Instant instant = Instant.ofEpochMilli(val);
        LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String formattedDateTime = dateTime.format(formatter);

        index += count;
        return formattedDateTime;
    }


    private boolean getBool() {
        byte b = getByte();
        return b != 0;
    }


    private int getInt() {
        int count = 4;
        byte[] bs = Arrays.copyOfRange(datas, index, count + index);
        toReverserBytes(bs);
        int val = ByteBuffer.wrap(bs).getInt();

        index += count;

        return val;
    }

    private short getUshort() {
        int count = 2;
        byte[] bs = Arrays.copyOfRange(datas, index, count + index);

        //toReverserBytes(bs);
        short ushortValue = (short) ((bs[0] & 0xFF) | ((bs[1] & 0xFF) << 8));

        index += count;

        return ushortValue;
    }

    private String getString(int count) {
        String str = new String(Arrays.copyOfRange(datas, index, count + index), StandardCharsets.UTF_8);

        index += count;

        return str;
    }

    private byte getByte() {
        int count = 1;
        byte[] bs = Arrays.copyOfRange(datas, index, count + index);

        index += count;

        return bs[0];
    }

    private void toReverserBytes(byte[] bytes) {
        for (int i = 0; i < bytes.length / 2; i++) {
            byte temp = bytes[i];
            bytes[i] = bytes[bytes.length - 1 - i];
            bytes[bytes.length - 1 - i] = temp;
        }
    }

}
