package com.steerinfo.meterwork.meterworkmonitor.rtdb;

import com.steerinfo.meterwork.meterworkmonitor.model.MeterWorkMonitor;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * MeterWorkMonitor ↔ Tarantool tuple（65 业务字段 + _dirty + _updated_at）。
 * 与线上 space format 对齐：66=_dirty(boolean), 67=_updated_at(number)。
 */
public final class MeterWorkMonitorTupleCodec {

    public static final int FIELD_COUNT = 67;
    public static final int IDX_POINT_NO = 1;
    public static final int IDX_LAST_TIME = 30;
    /** 1-based Tarantool field no */
    public static final int IDX_DIRTY = 66;
    /** 1-based Tarantool field no */
    public static final int IDX_UPDATED_AT = 67;

    private MeterWorkMonitorTupleCodec() {
    }

    public static List<Object> toTuple(MeterWorkMonitor m, boolean dirty) {
        List<Object> t = new ArrayList<>(FIELD_COUNT);
        t.add(nullToEmpty(m.getPointNo()));
        t.add(nullToEmpty(m.getPointName()));
        t.add(nullToEmpty(m.getValidWgt()));
        t.add(nullToEmpty(m.getValidCarno()));
        t.add(nullToEmpty(m.getValidTareTime()));
        t.add(nullToEmpty(m.getValidTimeInterval()));
        t.add(nullToEmpty(m.getValidParkStatus()));
        t.add(nullToEmpty(m.getValidExceedWgt()));
        t.add(nullToEmpty(m.getValidPredictionDiff()));
        t.add(nullToEmpty(m.getValidFlag()));
        t.add(nullToEmpty(m.getValidMatTime()));
        t.add(nullToEmpty(m.getCarMonitor()));
        t.add(numOrZero(m.getCarMonitorLvl()));
        t.add(nullToEmpty(m.getIsHelp()));
        t.add(nullToEmpty(m.getIsTakeOver()));
        t.add(nullToEmpty(m.getLedWriter()));
        t.add(numOrZero(m.getPrintNum()));
        t.add(nullToEmpty(m.getCollectionCode()));
        t.add(nullToEmpty(m.getIsOverWgt()));
        t.add(nullToEmpty(m.getUserNo()));
        t.add(nullToEmpty(m.getMonitorUserNo()));
        t.add(nullToEmpty(m.getSetCar()));
        t.add(nullToEmpty(m.getLedKeep()));
        t.add(nullToEmpty(m.getRfidCar()));
        t.add(nullToEmpty(m.getPhotoCar()));
        t.add(nullToEmpty(m.getScanCar()));
        t.add(nullToEmpty(m.getEditCar()));
        t.add(nullToEmpty(m.getCarErr()));
        t.add(nullToEmpty(m.getWgtErr()));
        t.add(dateToEpoch(m.getLastTime()));
        t.add(nullToEmpty(m.getStopOverTime()));
        t.add(nullToEmpty(m.getMsgInfo()));
        t.add(m.getWgt() == null ? 0L : m.getWgt());
        t.add(nullToEmpty(m.getIsRemote()));
        t.add(nullToEmpty(m.getWeighInstrumentModel()));
        t.add(nullToEmpty(m.getWeighInstrumentParam()));
        t.add(nullToEmpty(m.getMoxaIp()));
        t.add(nullToEmpty(m.getMoxaPort()));
        t.add(nullToEmpty(m.getValidLianda()));
        t.add(nullToEmpty(m.getIsOpenScanning()));
        t.add(nullToEmpty(m.getValidIsPre()));
        t.add(nullToEmpty(m.getUserIp()));
        t.add(nullToEmpty(m.getPowerState()));
        t.add(nullToEmpty(m.getDvrState()));
        t.add(nullToEmpty(m.getMoxaState()));
        t.add(nullToEmpty(m.getPlcState()));
        t.add(nullToEmpty(m.getLeftInfraredRayState()));
        t.add(nullToEmpty(m.getRightInfraredRayState()));
        t.add(nullToEmpty(m.getAmplifierState()));
        t.add(nullToEmpty(m.getLampState()));
        t.add(nullToEmpty(m.getSpotTypeNo()));
        t.add(nullToEmpty(m.getRedGreenLightState()));
        t.add(nullToEmpty(m.getFrontInfraredRayState()));
        t.add(nullToEmpty(m.getRearInfraredRayState()));
        t.add(nullToEmpty(m.getRfidState()));
        t.add(nullToEmpty(m.getValidArea()));
        t.add(nullToEmpty(m.getWeightStatus()));
        t.add(nullToEmpty(m.getFerroalloyConfirm()));
        t.add(nullToEmpty(m.getFerroalloyResult()));
        t.add(nullToEmpty(m.getZeroState()));
        t.add(numOrZero(m.getZeroWeight()));
        t.add(nullToEmpty(m.getIsZeroState()));
        t.add(nullToEmpty(m.getIsValidScan()));
        t.add(nullToEmpty(m.getIsEnableSound()));
        t.add(nullToEmpty(m.getPhotoCar2()));
        t.add(dirty);
        t.add(System.currentTimeMillis());
        return t;
    }

    public static MeterWorkMonitor fromTuple(List<?> t) {
        if (t == null || t.isEmpty()) {
            return null;
        }
        MeterWorkMonitor m = new MeterWorkMonitor();
        m.setPointNo(asString(t, 0));
        m.setPointName(asString(t, 1));
        m.setValidWgt(asString(t, 2));
        m.setValidCarno(asString(t, 3));
        m.setValidTareTime(asString(t, 4));
        m.setValidTimeInterval(asString(t, 5));
        m.setValidParkStatus(asString(t, 6));
        m.setValidExceedWgt(asString(t, 7));
        m.setValidPredictionDiff(asString(t, 8));
        m.setValidFlag(asString(t, 9));
        m.setValidMatTime(asString(t, 10));
        m.setCarMonitor(asString(t, 11));
        m.setCarMonitorLvl(asShort(t, 12));
        m.setIsHelp(asString(t, 13));
        m.setIsTakeOver(asString(t, 14));
        m.setLedWriter(asString(t, 15));
        m.setPrintNum(asShort(t, 16));
        m.setCollectionCode(asString(t, 17));
        m.setIsOverWgt(asString(t, 18));
        m.setUserNo(asString(t, 19));
        m.setMonitorUserNo(asString(t, 20));
        m.setSetCar(asString(t, 21));
        m.setLedKeep(asString(t, 22));
        m.setRfidCar(asString(t, 23));
        m.setPhotoCar(asString(t, 24));
        m.setScanCar(asString(t, 25));
        m.setEditCar(asString(t, 26));
        m.setCarErr(asString(t, 27));
        m.setWgtErr(asString(t, 28));
        m.setLastTime(asDate(t, 29));
        m.setStopOverTime(asString(t, 30));
        m.setMsgInfo(asString(t, 31));
        m.setWgt(asLong(t, 32));
        m.setIsRemote(asString(t, 33));
        m.setWeighInstrumentModel(asString(t, 34));
        m.setWeighInstrumentParam(asString(t, 35));
        m.setMoxaIp(asString(t, 36));
        m.setMoxaPort(asString(t, 37));
        m.setValidLianda(asString(t, 38));
        m.setIsOpenScanning(asString(t, 39));
        m.setValidIsPre(asString(t, 40));
        m.setUserIp(asString(t, 41));
        m.setPowerState(asString(t, 42));
        m.setDvrState(asString(t, 43));
        m.setMoxaState(asString(t, 44));
        m.setPlcState(asString(t, 45));
        m.setLeftInfraredRayState(asString(t, 46));
        m.setRightInfraredRayState(asString(t, 47));
        m.setAmplifierState(asString(t, 48));
        m.setLampState(asString(t, 49));
        m.setSpotTypeNo(asString(t, 50));
        m.setRedGreenLightState(asString(t, 51));
        m.setFrontInfraredRayState(asString(t, 52));
        m.setRearInfraredRayState(asString(t, 53));
        m.setRfidState(asString(t, 54));
        m.setValidArea(asString(t, 55));
        m.setWeightStatus(asString(t, 56));
        m.setFerroalloyConfirm(asString(t, 57));
        m.setFerroalloyResult(asString(t, 58));
        m.setZeroState(asString(t, 59));
        m.setZeroWeight(asShort(t, 60));
        m.setIsZeroState(asString(t, 61));
        m.setIsValidScan(asString(t, 62));
        m.setIsEnableSound(asString(t, 63));
        m.setPhotoCar2(asString(t, 64));
        return m;
    }

    public static boolean isDirty(List<?> t) {
        if (t == null || t.size() < IDX_DIRTY) {
            return false;
        }
        Object v = t.get(IDX_DIRTY - 1);
        return Boolean.TRUE.equals(v) || "true".equalsIgnoreCase(String.valueOf(v));
    }

    /**
     * 将 patch 中非空字段合并到 base（selective update 语义）。
     * patch是新的数据, base是旧的数据，patch中非空字段会覆盖base中的对应字段。
     * @param base 旧数据
     * @param patch 新数据
     */
    public static void mergeNonNull(MeterWorkMonitor base, MeterWorkMonitor patch) {
//        if (patch.getPointName() != null) {
//            base.setPointName(patch.getPointName());
//        }
        if (patch.getValidWgt() != null) {
            base.setValidWgt(patch.getValidWgt());
        }
        if (patch.getValidCarno() != null) {
            base.setValidCarno(patch.getValidCarno());
        }
        if (patch.getValidTareTime() != null) {
            base.setValidTareTime(patch.getValidTareTime());
        }
        if (patch.getValidTimeInterval() != null) {
            base.setValidTimeInterval(patch.getValidTimeInterval());
        }
        if (patch.getValidParkStatus() != null) {
            base.setValidParkStatus(patch.getValidParkStatus());
        }
        if (patch.getValidExceedWgt() != null) {
            base.setValidExceedWgt(patch.getValidExceedWgt());
        }
        if (patch.getValidPredictionDiff() != null) {
            base.setValidPredictionDiff(patch.getValidPredictionDiff());
        }
        if (patch.getValidFlag() != null) {
            base.setValidFlag(patch.getValidFlag());
        }
        if (patch.getValidMatTime() != null) {
            base.setValidMatTime(patch.getValidMatTime());
        }
        if (patch.getCarMonitor() != null) {
            base.setCarMonitor(patch.getCarMonitor());
        }
        if (patch.getCarMonitorLvl() != null) {
            base.setCarMonitorLvl(patch.getCarMonitorLvl());
        }
        if (patch.getIsHelp() != null) {
            base.setIsHelp(patch.getIsHelp());
        }
        if (patch.getIsTakeOver() != null) {
            base.setIsTakeOver(patch.getIsTakeOver());
        }
        if (patch.getLedWriter() != null) {
            base.setLedWriter(patch.getLedWriter());
        }
        if (patch.getPrintNum() != null) {
            base.setPrintNum(patch.getPrintNum());
        }
        if (patch.getCollectionCode() != null) {
            base.setCollectionCode(patch.getCollectionCode());
        }
        if (patch.getIsOverWgt() != null) {
            base.setIsOverWgt(patch.getIsOverWgt());
        }
        if (patch.getUserNo() != null) {
            base.setUserNo(patch.getUserNo());
        }
        if (patch.getMonitorUserNo() != null) {
            base.setMonitorUserNo(patch.getMonitorUserNo());
        }
        if (patch.getSetCar() != null) {
            base.setSetCar(patch.getSetCar());
        }
        if (patch.getLedKeep() != null) {
            base.setLedKeep(patch.getLedKeep());
        }
        if (patch.getRfidCar() != null) {
            base.setRfidCar(patch.getRfidCar());
        }
        if (patch.getPhotoCar() != null) {
            base.setPhotoCar(patch.getPhotoCar());
        }
        if (patch.getScanCar() != null) {
            base.setScanCar(patch.getScanCar());
        }
        if (patch.getEditCar() != null) {
            base.setEditCar(patch.getEditCar());
        }
        if (patch.getCarErr() != null) {
            base.setCarErr(patch.getCarErr());
        }
        if (patch.getWgtErr() != null) {
            base.setWgtErr(patch.getWgtErr());
        }
        if (patch.getLastTime() != null) {
            base.setLastTime(patch.getLastTime());
        }
        if (patch.getStopOverTime() != null) {
            base.setStopOverTime(patch.getStopOverTime());
        }
        if (patch.getMsgInfo() != null) {
            base.setMsgInfo(patch.getMsgInfo());
        }
        if (patch.getWgt() != null) {
            base.setWgt(patch.getWgt());
        }
        if (patch.getIsRemote() != null) {
            base.setIsRemote(patch.getIsRemote());
        }
        if (patch.getWeighInstrumentModel() != null) {
            base.setWeighInstrumentModel(patch.getWeighInstrumentModel());
        }
        if (patch.getWeighInstrumentParam() != null) {
            base.setWeighInstrumentParam(patch.getWeighInstrumentParam());
        }
        if (patch.getMoxaIp() != null) {
            base.setMoxaIp(patch.getMoxaIp());
        }
        if (patch.getMoxaPort() != null) {
            base.setMoxaPort(patch.getMoxaPort());
        }
        if (patch.getValidLianda() != null) {
            base.setValidLianda(patch.getValidLianda());
        }
        if (patch.getIsOpenScanning() != null) {
            base.setIsOpenScanning(patch.getIsOpenScanning());
        }
        if (patch.getValidIsPre() != null) {
            base.setValidIsPre(patch.getValidIsPre());
        }
        if (patch.getUserIp() != null) {
            base.setUserIp(patch.getUserIp());
        }
        if (patch.getPowerState() != null) {
            base.setPowerState(patch.getPowerState());
        }
        if (patch.getDvrState() != null) {
            base.setDvrState(patch.getDvrState());
        }
        if (patch.getMoxaState() != null) {
            base.setMoxaState(patch.getMoxaState());
        }
        if (patch.getPlcState() != null) {
            base.setPlcState(patch.getPlcState());
        }
        if (patch.getLeftInfraredRayState() != null) {
            base.setLeftInfraredRayState(patch.getLeftInfraredRayState());
        }
        if (patch.getRightInfraredRayState() != null) {
            base.setRightInfraredRayState(patch.getRightInfraredRayState());
        }
        if (patch.getAmplifierState() != null) {
            base.setAmplifierState(patch.getAmplifierState());
        }
        if (patch.getLampState() != null) {
            base.setLampState(patch.getLampState());
        }
        if (patch.getSpotTypeNo() != null) {
            base.setSpotTypeNo(patch.getSpotTypeNo());
        }
        if (patch.getRedGreenLightState() != null) {
            base.setRedGreenLightState(patch.getRedGreenLightState());
        }
        if (patch.getFrontInfraredRayState() != null) {
            base.setFrontInfraredRayState(patch.getFrontInfraredRayState());
        }
        if (patch.getRearInfraredRayState() != null) {
            base.setRearInfraredRayState(patch.getRearInfraredRayState());
        }
        if (patch.getRfidState() != null) {
            base.setRfidState(patch.getRfidState());
        }
        if (patch.getValidArea() != null) {
            base.setValidArea(patch.getValidArea());
        }
        if (patch.getWeightStatus() != null) {
            base.setWeightStatus(patch.getWeightStatus());
        }
        if (patch.getFerroalloyConfirm() != null) {
            base.setFerroalloyConfirm(patch.getFerroalloyConfirm());
        }
        if (patch.getFerroalloyResult() != null) {
            base.setFerroalloyResult(patch.getFerroalloyResult());
        }
        if (patch.getZeroState() != null) {
            base.setZeroState(patch.getZeroState());
        }
        if (patch.getZeroWeight() != null) {
            base.setZeroWeight(patch.getZeroWeight());
        }
        if (patch.getIsZeroState() != null) {
            base.setIsZeroState(patch.getIsZeroState());
        }
        if (patch.getIsValidScan() != null) {
            base.setIsValidScan(patch.getIsValidScan());
        }
        if (patch.getIsEnableSound() != null) {
            base.setIsEnableSound(patch.getIsEnableSound());
        }
        if (patch.getPhotoCar2() != null) {
            base.setPhotoCar2(patch.getPhotoCar2());
        }
    }

    private static String nullToEmpty(String s) {
        return s == null ? "" : s;
    }

    private static Number numOrZero(Number n) {
        return n == null ? 0 : n;
    }

    private static Long dateToEpoch(Date d) {
        return d == null ? null : d.getTime();
    }

    private static Object at(List<?> t, int idx) {
        return idx < t.size() ? t.get(idx) : null;
    }

    private static String asString(List<?> t, int idx) {
        Object v = at(t, idx);
        if (v == null) {
            return null;
        }
        String s = String.valueOf(v);
        return s.isEmpty() ? null : s;
    }

    private static Short asShort(List<?> t, int idx) {
        Object v = at(t, idx);
        if (v == null) {
            return null;
        }
        if (v instanceof Number) {
            return ((Number) v).shortValue();
        }
        try {
            return Short.valueOf(String.valueOf(v));
        } catch (NumberFormatException e) {
            return null;
        }
    }

    private static Long asLong(List<?> t, int idx) {
        Object v = at(t, idx);
        if (v == null) {
            return null;
        }
        if (v instanceof Number) {
            return ((Number) v).longValue();
        }
        try {
            return Long.valueOf(String.valueOf(v));
        } catch (NumberFormatException e) {
            return null;
        }
    }

    private static Date asDate(List<?> t, int idx) {
        Object v = at(t, idx);
        if (v == null) {
            return null;
        }
        if (v instanceof Date) {
            return (Date) v;
        }
        if (v instanceof Number) {
            long epoch = ((Number) v).longValue();
            return epoch <= 0 ? null : new Date(epoch);
        }
        return null;
    }
}
