package org.lovebing.reactnative.baidumap.util;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.facebook.react.bridge.ReadableType;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.Iterator;

public class JsonUtils {
    /**
     * 将 WritableMap 转换为 JSON 字符串
     */
    public static String writableMapToJsonString(WritableMap writableMap) {
        if (writableMap == null) {
            return "{}";
        }

        try {
            JSONObject jsonObject = convertWritableMapToJsonObject(writableMap);
            return jsonObject.toString();
        } catch (JSONException e) {
            e.printStackTrace();
            return "{}";
        }
    }

    /**
     * 将 WritableMap 转换为 JSONObject
     */
    private static JSONObject convertWritableMapToJsonObject(ReadableMap readableMap) throws JSONException {
        JSONObject jsonObject = new JSONObject();

        if (readableMap == null) {
            return jsonObject;
        }

        ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
        while (iterator.hasNextKey()) {
            String key = iterator.nextKey();
            ReadableType type = readableMap.getType(key);

            switch (type) {
                case Null:
                    jsonObject.put(key, JSONObject.NULL);
                    break;
                case Boolean:
                    jsonObject.put(key, readableMap.getBoolean(key));
                    break;
                case Number:
                    // 判断是整数还是浮点数
                    double number = readableMap.getDouble(key);
                    if (number == Math.floor(number)) {
                        jsonObject.put(key, (int) number);
                    } else {
                        jsonObject.put(key, number);
                    }
                    break;
                case String:
                    jsonObject.put(key, readableMap.getString(key));
                    break;
                case Map:
                    jsonObject.put(key, convertWritableMapToJsonObject(readableMap.getMap(key)));
                    break;
                case Array:
                    jsonObject.put(key, convertWritableArrayToJsonArray(readableMap.getArray(key)));
                    break;
            }
        }

        return jsonObject;
    }

    /**
     * 将 WritableArray 转换为 JSONArray
     */
    private static JSONArray convertWritableArrayToJsonArray(ReadableArray readableArray) throws JSONException {
        JSONArray jsonArray = new JSONArray();

        if (readableArray == null) {
            return jsonArray;
        }

        for (int i = 0; i < readableArray.size(); i++) {
            ReadableType type = readableArray.getType(i);

            switch (type) {
                case Null:
                    jsonArray.put(JSONObject.NULL);
                    break;
                case Boolean:
                    jsonArray.put(readableArray.getBoolean(i));
                    break;
                case Number:
                    double number = readableArray.getDouble(i);
                    if (number == Math.floor(number)) {
                        jsonArray.put((int) number);
                    } else {
                        jsonArray.put(number);
                    }
                    break;
                case String:
                    jsonArray.put(readableArray.getString(i));
                    break;
                case Map:
                    jsonArray.put(convertWritableMapToJsonObject(readableArray.getMap(i)));
                    break;
                case Array:
                    jsonArray.put(convertWritableArrayToJsonArray(readableArray.getArray(i)));
                    break;
            }
        }

        return jsonArray;
    }

    /**
     * 将 JSON 字符串转换为 WritableMap
     */
    public static WritableMap jsonStringToWritableMap(String jsonString) {
        if (jsonString == null || jsonString.isEmpty()) {
            return Arguments.createMap();
        }

        try {
            JSONObject jsonObject = new JSONObject(jsonString);
            return convertJsonObjectToWritableMap(jsonObject);
        } catch (JSONException e) {
            e.printStackTrace();
            return Arguments.createMap();
        }
    }

    /**
     * 将 JSONObject 转换为 WritableMap
     */
    private static WritableMap convertJsonObjectToWritableMap(JSONObject jsonObject) throws JSONException {
        WritableMap writableMap = Arguments.createMap();

        if (jsonObject == null) {
            return writableMap;
        }

        Iterator<String> keys = jsonObject.keys();
        while (keys.hasNext()) {
            String key = keys.next();
            Object value = jsonObject.get(key);

            if (value == null || value == JSONObject.NULL) {
                writableMap.putNull(key);
            } else if (value instanceof Boolean) {
                writableMap.putBoolean(key, (Boolean) value);
            } else if (value instanceof Integer) {
                writableMap.putInt(key, (Integer) value);
            } else if (value instanceof Double) {
                writableMap.putDouble(key, (Double) value);
            } else if (value instanceof Long) {
                writableMap.putDouble(key, ((Long) value).doubleValue());
            } else if (value instanceof String) {
                writableMap.putString(key, (String) value);
            } else if (value instanceof JSONObject) {
                writableMap.putMap(key, convertJsonObjectToWritableMap((JSONObject) value));
            } else if (value instanceof JSONArray) {
                writableMap.putArray(key, convertJsonArrayToWritableArray((JSONArray) value));
            }
        }

        return writableMap;
    }

    /**
     * 将 JSONArray 转换为 WritableArray
     */
    private static WritableArray convertJsonArrayToWritableArray(JSONArray jsonArray) throws JSONException {
        WritableArray writableArray = Arguments.createArray();

        if (jsonArray == null) {
            return writableArray;
        }

        for (int i = 0; i < jsonArray.length(); i++) {
            Object value = jsonArray.get(i);

            if (value == null || value == JSONObject.NULL) {
                writableArray.pushNull();
            } else if (value instanceof Boolean) {
                writableArray.pushBoolean((Boolean) value);
            } else if (value instanceof Integer) {
                writableArray.pushInt((Integer) value);
            } else if (value instanceof Double) {
                writableArray.pushDouble((Double) value);
            } else if (value instanceof Long) {
                writableArray.pushDouble(((Long) value).doubleValue());
            } else if (value instanceof String) {
                writableArray.pushString((String) value);
            } else if (value instanceof JSONObject) {
                writableArray.pushMap(convertJsonObjectToWritableMap((JSONObject) value));
            } else if (value instanceof JSONArray) {
                writableArray.pushArray(convertJsonArrayToWritableArray((JSONArray) value));
            }
        }

        return writableArray;
    }
}
