package com.malk.utils;

import cn.hutool.core.util.ObjectUtil;
import com.malk.server.common.McException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

@Slf4j
public abstract class UtilMap {

    /**
     * Map创建时的忽略策略枚举
     */
    public enum MapIgnore {
        NULL,           // 忽略null
        EMPTY_STRING,   // 忽略空字符串""
        BLANK_STRING,   // 忽略空白字符串(含空格)
        ZERO,           // 忽略数值0
        EMPTY_LIST,     // 忽略空集合
        EMPTY_MAP       // 忽略空Map
    }

    /************* 快速创建map ************/

    /**
     * 快速创建map [key, Objects]
     */
    public static Map<String, Object> map(String keys, Object... values) {
        String[] props = keys.split(", ");
        if (props.length != values.length) {
            McException.assertParamException_Null(keys);
        }
        Map<String, Object> map = new HashMap<>();
        Arrays.stream(values).forEach(UtilMc.consumerWithIndex((item, index) -> {
            map.put(props[index], item);
        }));
        return map;
    }

    /**
     * 快速创建map [key, Objects] 忽略null和空字符串
     */
    public static Map<String, Object> mapNotNull(String keys, Object... values) {
        return mapWithIgnore(keys, EnumSet.of(MapIgnore.NULL, MapIgnore.BLANK_STRING), values);
    }

    /**
     * 快速创建map [key, Objects] 支持自定义忽略策略
     * @param keys 字段名，逗号分隔
     * @param ignores 忽略策略集合
     * @param values 字段值
     */
    public static Map<String, Object> mapWithIgnore(String keys, EnumSet<MapIgnore> ignores, Object... values) {
        String[] props = keys.split(", ");
        if (props.length != values.length) {
            McException.assertParamException_Null(keys);
        }
        Map<String, Object> map = new HashMap<>();
        Arrays.stream(values).forEach(UtilMc.consumerWithIndex((item, index) -> {
            if (!shouldIgnore(item, ignores)) {
                map.put(props[index], item);
            }
        }));
        return map;
    }

    /**
     * 判断值是否应该被忽略
     */
    private static boolean shouldIgnore(Object value, EnumSet<MapIgnore> ignores) {
        if (ignores == null || ignores.isEmpty()) {
            return false;
        }
        // 忽略null
        if (ignores.contains(MapIgnore.NULL) && ObjectUtil.isNull(value)) {
            return true;
        }
        if (value == null) {
            return false;
        }
        String strVal = String.valueOf(value);
        // 忽略空字符串
        if (ignores.contains(MapIgnore.EMPTY_STRING) && "".equals(strVal)) {
            return true;
        }
        // 忽略空白字符串
        if (ignores.contains(MapIgnore.BLANK_STRING) && StringUtils.isBlank(strVal)) {
            return true;
        }
        // 忽略"null"字符串
        if (ignores.contains(MapIgnore.NULL) && "null".equals(strVal)) {
            return true;
        }
        // 忽略数值0
        if (ignores.contains(MapIgnore.ZERO) && value instanceof Number) {
            if (((Number) value).doubleValue() == 0) {
                return true;
            }
        }
        // 忽略空集合
        if (ignores.contains(MapIgnore.EMPTY_LIST) && value instanceof Collection) {
            if (((Collection<?>) value).isEmpty()) {
                return true;
            }
        }
        // 忽略空Map
        if (ignores.contains(MapIgnore.EMPTY_MAP) && value instanceof Map) {
            if (((Map<?, ?>) value).isEmpty()) {
                return true;
            }
        }
        return false;
    }

    /**
     * 快速创建map [key, Strings]
     */
    public static Map<String, String> map(String keys, String values) {
        if (UtilString.isBlankCompatNull(keys) || UtilString.isBlankCompatNull(values)) {
            return UtilMap.empty();
        }
        String[] props = keys.split(", ");
        String[] contents = values.split(", ");
        if (props.length != contents.length) {
            McException.assertParamException_Null(keys);
        }
        Map<String, String> map = new HashMap<>();
        Arrays.stream(contents).forEach(UtilMc.consumerWithIndex((item, index) -> {
            map.put(props[index], String.valueOf(item));
        }));
        return map;
    }

    /**
     * 判断Map中指定字段值是否相等
     * @param data Map数据
     * @param key 字段名
     * @param expected 期望值
     */
    public static boolean fieldEquals(Map data, String key, Object expected) {
        if (ObjectUtil.isNull(data)) {
            return false;
        }
        Object value = data.get(key);
        if (ObjectUtil.isNull(value) && ObjectUtil.isNull(expected)) {
            return true;
        }
        if (ObjectUtil.isNull(value) || ObjectUtil.isNull(expected)) {
            return false;
        }
        return value.equals(expected);
    }

    /**
     * 判断Map中指定字段值是否相等（字符串比较）
     * @param data Map数据
     * @param key 字段名
     * @param expected 期望值
     */
    public static boolean fieldEqualsString(Map data, String key, String expected) {
        if (ObjectUtil.isNull(data)) {
            return false;
        }
        String value = getString(data, key);
        if (StringUtils.isBlank(value) && StringUtils.isBlank(expected)) {
            return true;
        }
        return value.equals(expected);
    }

    /**
     * 快速创建map [保留skeys, 取值ckeys] 源值为null时不赋值
     */
    public static Map<String, Object> map(String skeys, String ckeys, Map map) {
        return map(skeys, ckeys, map, false);
    }

    /**
     * 快速创建map [保留skeys, 取值ckeys] 支持字段覆盖
     * @param skeys 目标字段名，逗号分隔
     * @param ckeys 源字段名，逗号分隔
     * @param map 源Map
     * @param includeNull 是否包含null值（true时null也会覆盖）
     */
    public static Map<String, Object> map(String skeys, String ckeys, Map map, boolean includeNull) {
        String[] sprops = skeys.split(", ");
        String[] cprops = ckeys.split(", ");
        if (sprops.length != cprops.length) {
            McException.assertParamException_Null(skeys);
        }
        Map data = new HashMap();
        Arrays.stream(cprops).forEach(UtilMc.consumerWithIndex((item, index) -> {
            Object value = map.get(item);
            if (includeNull || value != null) {
                data.put(sprops[index], value);
            }
        }));
        return data;
    }

    /**
     * 快速创建map [合并skeys, 取值ckeys]
     */
    public static void map(String skeys, String ckeys, Map sMap, Map cMap) {
        sMap.putAll(map(skeys, ckeys, cMap));
    }

    /// 创建空对象
    public static Map empty() {
        return new HashedMap();
    }

    /// 判定 & 创建空对象
    public static Map empty(Map data) {
        if (ObjectUtil.isNotNull(data)) {
            return data;
        }
        return new HashedMap();
    }

    /************* 赋值 ************/

    /**
     * 赋值 [为空对象null, 忽略]
     */
    public static Map putNotNull(Map data, String key, Object value) {
        if (ObjectUtil.isNull(data)) {
            data = new HashMap();
        }
        if (ObjectUtil.isNotNull(value)) {
            data.put(key, value);
        }
        return data;
    }

    /**
     * 赋值 [为空字符串, 忽略]
     */
    public static Map putNotEmpty(Map data, String key, String value) {
        if (ObjectUtil.isNull(data)) {
            data = new HashMap();
        }
        if (StringUtils.isNotBlank(value)) {
            data.put(key, value);
        }
        return data;
    }

    /**
     * 非空对象全量合并
     */
    public static Map putAll(Map data, Map value) {
        if (ObjectUtil.isNull(data)) {
            if (ObjectUtil.isNull(value)) {
                return empty();
            }
            return value;
        }
        if (ObjectUtil.isNotNull(value)) {
            data.putAll(value);
        }
        return data;
    }

    /**
     * 赋值 [值为0, 忽略]
     */
    public static Map putNotZero(Map data, String key, Object value) {
        float val = 0.f;
        try {
            val = Float.valueOf(String.valueOf(value));
        } catch (Exception e) {
            data.put(key, value);
        }
        if (val != 0.f) {
            data.put(key, value);
        }
        return data;
    }

    /**
     * 赋值 [原值为空赋值默认值]
     */
    public static Map put(Map data, String key, Object defaultValue) {
        if (ObjectUtil.isNull(data)) {
            data = empty(data);
        }
        Object value = data.get(key);
        if (ObjectUtil.isNull(value)) {
            value = defaultValue;
        }
        data.put(key, value);
        return data;
    }

    /**
     * 赋值 [赋值为空赋值默认值]
     */
    public static Map put(Map data, String key, Object value, Object defaultValue) {
        data = empty(data);
        if (ObjectUtil.isNull(value)) {
            value = defaultValue;
        }
        data.put(key, value);
        return data;
    }

    /************* 取值 ************/

    /**
     * 取值 [String.valueOf 避免空指针]
     */
    public static String getString(Map data, String key) {
        if (data.containsKey(key)) {
            // 不能判空字符串
            if (ObjectUtil.isNull(data.get(key))) {
                return "";
            }
            String value = String.valueOf(data.get(key));
            // 屏蔽空指针转换
            if (value.equals("null")) {
                return "";
            }
            return value;
        }
        return "";
    }

    /**
     * 取值 [转为 long]
     */
    public static long getLong(Map data, String key) {
        McException.assertParamException_Null(data, key);
        return Long.valueOf(getString(data, key)) + 0L;
    }

    /**
     * 取值 [转为 int]
     */
    public static int getInt(Map data, String key) {
        String txt = getString(data, key);
        if (StringUtils.isBlank(txt)) {
            return 0;
        }
        return Integer.valueOf(txt);
    }

    /**
     * 取值 [转为 float]
     */
    public static Float getFloat(Map data, String key) {
        String txt = getString(data, key);
        if (StringUtils.isBlank(txt)) {
            return 0f;
        }
        return Float.valueOf(txt);
    }

    public static Double getDouble(Map data, String key) {
        String txt = getString(data, key);
        if (StringUtils.isBlank(txt)) {
            return 0d;
        }
        return Double.valueOf(txt);
    }

    /**
     * 取值 [转为 bool]
     */
    public static Boolean getBoolean(Map data, String key) {
        return Boolean.valueOf(getString(data, key));
    }

    /**
     * 取值 [为空返回默认值]
     */
    public static Object get_default(Map data, String key, Object defaultValue) {
        Object value = data.get(key);
        if (ObjectUtil.isNull(value)) {
            return defaultValue;
        }
        return value;
    }

    /**
     * 取值 [为空返回默认字符串]
     */
    public static String getString_default(Map data, String key, String defaultValue) {
        String value = getString(data, key);
        if (StringUtils.isBlank(value)) {
            return defaultValue;
        }
        return value;
    }

    /**
     * 取值 [未定key, 取第一个命中]
     */
    public static Object get_first(Map data, String... keys) {
        Object value = null;
        for (String key : keys) {
            if (data.containsKey(key)) {
                value = data.get(key);
                break;
            }
        }
        return value;
    }

    /**
     * 取值 String [未定key, 取第一个命中]
     */
    public static String getString_first(Map data, String... keys) {
        String value = "";
        for (String key : keys) {
            // 字段 + 值判定
            if (data.containsKey(key) && StringUtils.isNotBlank(getString(data, key))) {
                value = UtilString.stringFormatNull(data, key);
                break;
            }
        }
        return value;
    }

    /**
     * 取值 List
     */
    public static List getList(Map data, String key) {
        if (data.containsKey(key)) {
            Object val = data.get(key);
            if (val instanceof List) {
                return (List) val;
            }
        }
        return new ArrayList();
    }

    /**
     * 取值 Map
     */
    public static Map getMap(Map data, String key) {
        if (data.containsKey(key)) {
            Object val = data.get(key);
            if (val instanceof Map) {
                return (Map) val;
            }
            return (Map) data.get(key);
        }
        return new HashedMap();
    }

    /************* 判定 ************/

    /**
     * 是否空字符串
     */
    public static boolean isBlankString(Map data, String key) {
        return StringUtils.isBlank(getString(data, key));
    }

    /**
     * 是否不为空字符串
     */
    public static boolean isNotBlankString(Map data, String key) {
        return StringUtils.isNotBlank(getString(data, key));
    }
}
