package com.iotize.plugin.cordova.zebrarfid;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.zebra.rfid.api3.LOCK_DATA_FIELD;
import com.zebra.rfid.api3.LOCK_PRIVILEGE;
import com.zebra.rfid.api3.MEMORY_BANK;
import com.zebra.rfid.api3.RFIDReader;
import com.zebra.rfid.api3.TagData;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.Arrays;
import java.util.Collection;

public class DataConverter {

    @NonNull
    public static JSONObject toJSONObject(@NonNull TagData tag) throws JSONException {
        JSONObject tagJson = new JSONObject();
        tagJson.put("id", tag.getTagID());
        tagJson.put("peakRSSI", tag.getPeakRSSI());
        tagJson.put("event", tag.getTagEvent());
        tagJson.put("pc", tag.getPC());
        tagJson.put("antennaId", tag.getAntennaID());
        tagJson.put("memoryBank", tag.getMemoryBank());
        // tagJson.put("memoryBankData", tag.getMemoryBankData());
        tagJson.put("accessOperationStatus", tag.getAccessOperationStatus());
        tagJson.put("channel", tag.getChannel());
        tagJson.put("channelIndex", tag.getChannelIndex());
        tagJson.put("seenCount", tag.getTagSeenCount());
        //tagJson.put("controlData", tag.getTagControlData());
        if (tag.LocationInfo != null) {
            tagJson.put("distance", tag.LocationInfo.getRelativeDistance());
        }
        // tagJson.put("numberOfWords", tag.getNumberOfWords());
        return tagJson;
    }

    @NonNull
    public static JSONObject toJSONObject(@NonNull RFIDReader reader) throws JSONException {
        JSONObject result = new JSONObject();
        result.put("hostname", reader.getHostName());
        result.put("transport", reader.getTransport());
        result.put("port", reader.getPort());
        return result;
    }

    @NonNull
    static MEMORY_BANK getMemoryBankFromOrdinal(Integer memoryBankInt) {
        MEMORY_BANK memoryBank = memoryBankInt != null ? MEMORY_BANK.GetMemoryBankValue(memoryBankInt) : MEMORY_BANK.MEMORY_BANK_USER;
        return memoryBank == null ? MEMORY_BANK.MEMORY_BANK_USER : memoryBank;
    }

    @NonNull
    public static LOCK_PRIVILEGE getLockPrivilegeFromOrdinal(@Nullable Integer value) throws Exception {
        if (value != null) {
            if (LOCK_PRIVILEGE.LOCK_PRIVILEGE_PERMA_LOCK.ordinal == value) {
                return LOCK_PRIVILEGE.LOCK_PRIVILEGE_PERMA_LOCK;
            } else if (LOCK_PRIVILEGE.LOCK_PRIVILEGE_NONE.ordinal == value) {
                return LOCK_PRIVILEGE.LOCK_PRIVILEGE_NONE;
            } else if (LOCK_PRIVILEGE.LOCK_PRIVILEGE_UNLOCK.ordinal == value) {
                return LOCK_PRIVILEGE.LOCK_PRIVILEGE_UNLOCK;
            } else if (LOCK_PRIVILEGE.LOCK_PRIVILEGE_READ_WRITE.ordinal == value) {
                return LOCK_PRIVILEGE.LOCK_PRIVILEGE_READ_WRITE;
            } else if (LOCK_PRIVILEGE.LOCK_PRIVILEGE_PERMA_UNLOCK.ordinal == value) {
                return LOCK_PRIVILEGE.LOCK_PRIVILEGE_PERMA_UNLOCK;
            }
        }
        throw new Exception("Invalid lock privilege ordinal value: " + value);
    }

    @NonNull
    public static LOCK_DATA_FIELD getDataFieldFromOrdinal(@Nullable Integer value) throws Exception {
        if (value != null) {
            if (LOCK_DATA_FIELD.LOCK_KILL_PASSWORD.ordinal == value) {
                return LOCK_DATA_FIELD.LOCK_KILL_PASSWORD;
            }
            else if (LOCK_DATA_FIELD.LOCK_USER_MEMORY.ordinal == value) {
                return LOCK_DATA_FIELD.LOCK_USER_MEMORY;
            } else if (LOCK_DATA_FIELD.LOCK_ACCESS_PASSWORD.ordinal == value) {
                return LOCK_DATA_FIELD.LOCK_ACCESS_PASSWORD;
            }else if (LOCK_DATA_FIELD.LOCK_EPC_MEMORY.ordinal == value) {
                return LOCK_DATA_FIELD.LOCK_EPC_MEMORY;
            }else if (LOCK_DATA_FIELD.LOCK_TID_MEMORY.ordinal == value) {
                return LOCK_DATA_FIELD.LOCK_TID_MEMORY;
            }
        }
        throw new Exception("Invalid data field ordinal value: " + value);
    }

    @NonNull
    public static JSONArray toJSArray(@Nullable Collection<TagData> myTags) throws JSONException {
        JSONArray tagArray = new JSONArray();
        if (myTags != null) {
            for (TagData tagData : myTags) {
                tagArray.put(DataConverter.toJSONObject(tagData));
            }
        }
        return tagArray;
    }

    @NonNull
    public static JSONObject toJSONObject(@NonNull PluginError err)  {
        JSONObject res = new JSONObject();
        try {
            res.put("message", err.getMessage());
            res.put("code", err.code);
        }
        catch (JSONException e) { }
        return res;
    }

    @NonNull
    public static JSONObject toJSONObject(@NonNull Throwable err) {
        if (err instanceof PluginError) {
            return toJSONObject((PluginError) err);
        }
        JSONObject res = new JSONObject();
        try {
            res.put("message", err.getMessage());
            res.put("code", PluginError.Code.UNKNOWN);
        }
        catch (JSONException e) { }
        return res;
    }

    @NonNull
    public static JSONObject createErrorObject(@NonNull String msg, @NonNull String code) throws JSONException {
        JSONObject res = new JSONObject();
        res.put("message", msg);
        res.put("code", code);
        return res;
    }

    @NonNull
    public static String getHexStringWithPadding(@Nullable String data) {
        if (data == null) {
            return "";
        }
        int dataLength = data.length();
        int paddingSize = (4 - (dataLength % 4)) % 4;
        if (paddingSize > 0) {
            return data + "0".repeat(paddingSize);
        }
        return data;
    }

    public static long getAccessPassword(String accessPassword) {
        return accessPassword == null ? 0 : Long.decode("0x" + accessPassword);
    }

}
