package com.boman.web.core.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.boman.common.core.utils.SecurityUtils;
import com.boman.common.core.utils.StringUtils;
import com.boman.common.core.utils.obj.ObjectUtils;
import com.boman.domain.GenTableColumn;
import com.boman.domain.exception.UnknownColumnException;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;

import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import static com.boman.common.core.utils.obj.ObjectUtils.*;
import static com.boman.domain.constant.FormDataConstant.*;

/**
 * @author shiqian
 * @date 2021年04月13日 15:37
 **/
public class ColumnUtils {

    /**
     * 功能描述: 新增或者修改的时候，是否需要给修改人修改时间赋值
     *
     * @param columns     所有的列
     * @param jsonObject  需要返回的数据
     * @param currentTime currentTime
     * @param isSave      新增true、修改false
     */
    public static void packUpdateByAndTime(List<GenTableColumn> columns, JSONObject jsonObject, Timestamp currentTime, boolean isSave) {
        for (GenTableColumn column : columns) {
            String columnName = column.getColumnName();
            if (UPDATE_BY.equalsIgnoreCase(columnName)) {
                jsonObject.put(columnName, SecurityUtils.getUsername());
                continue;
            }

            if (UPDATE_TIME.equalsIgnoreCase(columnName)) {
                jsonObject.put(columnName, currentTime);
                continue;
            }

            if (isSave) {
                if (CREATE_TIME.equalsIgnoreCase(columnName)) {
                    jsonObject.put(columnName, currentTime);
                    continue;
                }
                if (CREATE_BY.equalsIgnoreCase(columnName)) {
                    jsonObject.put(columnName, SecurityUtils.getUsername());
                    continue;
                }
                if (DATETIME.equalsIgnoreCase(column.getColumnType())) {
                    Object value = jsonObject.getTimestamp(columnName);
                    if (isNotEmpty(value)) {
                        jsonObject.put(columnName, jsonObject.getTimestamp(columnName));
                    }
                }
            } else {
                // 修改时，修改非创建时间的其他时间类型
                if (DATETIME.equalsIgnoreCase(column.getColumnType())) {
                    if (!CREATE_TIME.equalsIgnoreCase(columnName) && isNotEmpty(jsonObject.get(columnName))) {
                        jsonObject.put(columnName, jsonObject.getTimestamp(columnName));
                    }
                }
            }
        }
    }

    /**
     * 功能描述: 把新增可见或者修改可见或者.....的列过滤出来
     *
     * @param allColumns 所有的列
     * @param sort       那六个1的顺序 [1,1,1,1,1,1]
     *                   sort=0  =>  新增可见
     *                   sort=1  =>  新增可修改
     *                   sort=2  =>  修改可见
     *                   sort=3  =>  修改可修改
     *                   sort=4  =>  列表可见
     *                   sort=5  =>  列表可修改
     * @return List<GenTableColumn>
     */
    public static List<GenTableColumn> filterData(List<GenTableColumn> allColumns, int sort, Predicate<String> predicate) {
        assert sort < 6;
        List<GenTableColumn> returnData = Lists.newArrayListWithCapacity(16);
        for (GenTableColumn allColumn : allColumns) {
            if (!HR.equalsIgnoreCase(allColumn.getHtmlType())) {
                String[] maskArray = requireNonNull(allColumn.getMask(), "mask is empty").split("");
                assert maskArray.length == 6;
                // sort
                String insertVisible = maskArray[sort];
                if (predicate.test(insertVisible)) {
                    returnData.add(allColumn);
                }
            }

        }

        return returnData;
    }

    /**
     * 功能描述: 按照predicate的规则过滤allColumns中包含data并且符合过滤规则的数据, <p>过滤掉hr !!!</p>
     *
     * @param allColumns 所有的列
     * @param sort       同{@link ColumnUtils#filterData(java.util.List, int, java.util.function.Predicate)}
     * @param data       从其中过滤符合规则的数据，data中字符串全部是大写的
     * @param predicate  predicate
     * @return JSONArray
     */
    public static JSONArray filterData(List<GenTableColumn> allColumns, int sort, JSONArray data, Predicate<String> predicate) {
        assert sort < 6;
        JSONArray returnData = new JSONArray();
        boolean dataIsEmpty = isEmpty(data);
        if (dataIsEmpty) {
            // data为空，拿出所有列中列表可见的
            for (GenTableColumn allColumn : allColumns) {
                if (HR.equalsIgnoreCase(allColumn.getHtmlType())) {
                    continue;
                }

                String columnName = allColumn.getColumnName();
                String mask = requireNonNull(allColumn.getMask(), "mask is empty, columnName = [" + allColumn.getColumnName() + "]");
                String[] maskArray = mask.split("");
                assert maskArray.length == 6;
                String maskValue = maskArray[sort];
                if (predicate.test(maskValue)) {
                    returnData.add(columnName);
                }
            }
        } else {
            // data不为空，拿出前端传过来的列中可见的
            for (GenTableColumn allColumn : allColumns) {
                String columnName = allColumn.getColumnName();
                if (HR.equalsIgnoreCase(allColumn.getHtmlType())) {
                    continue;
                }
                if (data.contains(columnName.toUpperCase()) || data.contains(columnName.toLowerCase())) {
                    String mask = requireNonNull(allColumn.getMask(), "mask is empty, columnName = [" + allColumn.getColumnName() + "]");
                    String[] maskArray = mask.split("");
                    assert maskArray.length == 6;
                    String maskValue = maskArray[sort];
                    if (predicate.test(maskValue)) {
                        returnData.add(columnName);
                    }
                }
            }
        }


        return returnData;
    }

    public static String parseVariables(String variables) {
        return variables.replaceAll("\\$", "");
    }

    /**
     * 功能描述: 前台传过来的列是否都在表中
     *
     * @param target 前台传过来的列
     * @param origin 此表对应的所有的列
     */
    public static void checkColumn(Map<String, Object> target, List<GenTableColumn> origin) {
        if (MapUtils.isEmpty(target) || ObjectUtils.isEmpty(origin)) {
            return;
        }

        String tableName = origin.get(0).getTableName();
        List<String> all = map(origin, GenTableColumn::getColumnName);
        for (Map.Entry<String, Object> entry : target.entrySet()) {
            String columnName = entry.getKey();
            if (!all.contains(columnName.toLowerCase())) {
                throw new UnknownColumnException("此表 [" + tableName + "]中没有 [" + columnName + "] 字段");
            }
        }
    }

    /**
     * 功能描述: 前台传过来的列是否都在表中, List中的泛型必须为String
     *
     * @param target 前台传过来的列
     * @param origin 此表对应的所有的列
     */
    public static void checkColumn(List<Object> target, List<GenTableColumn> origin) {
        if (ObjectUtils.isEmpty(target) || ObjectUtils.isEmpty(origin)) {
            return;
        }

        String tableName = origin.get(0).getTableName();
        List<String> all = map(origin, GenTableColumn::getColumnName);
        for (Object obj : target) {
            String columnName = (String) obj;
            if (!all.contains(columnName.toLowerCase()) || !all.contains(columnName.toUpperCase())) {
                throw new UnknownColumnException("此表 [" + tableName + "]中没有 [" + columnName + "] 字段");
            }
        }
    }

    /**
     * 功能描述: 根据从数据库查出来的返回值来确实是否是blob, 转为字符串! 转为字符串! 转为字符串!
     *
     * @param isContainsBlob 此表中的字段是否含有blob的列, true含
     * @param result         result
     */
    public static void handlerBlobWithJSONObject(Boolean isContainsBlob, List<JSONObject> result) {
        // 不包含
        if (BooleanUtils.isFalse(isContainsBlob)) {
            return;
        }

        for (JSONObject jsonObject : result) {
            for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
                Object value = entry.getValue();
                if (isNotEmpty(value) && BYTE_ARRAY.equals(value.getClass().getSimpleName())) {
                    entry.setValue(byteToString(((byte[]) value)));
                }
            }
        }
    }

    /**
     * 功能描述: 根据从数据库查出来的返回值来确实是否是blob, 转为字符串! 转为字符串! 转为字符串!
     *
     * @param result result
     */
    public static void handlerBlobWithTableColumn(Boolean isContainsBlob, List<GenTableColumn> result) {
        // 不包含
        if (BooleanUtils.isFalse(isContainsBlob)) {
            return;
        }

        for (GenTableColumn column : result) {
            Object value = column.getColumnValue();
            if (isNotEmpty(value) && BYTE_ARRAY.equals(value.getClass().getSimpleName())) {
                column.setColumnValue(byteToString(((byte[]) value)));
            }
        }
    }

    public static String byteToString(byte[] bytes) {
        String result = "";
        if (ArrayUtils.isNotEmpty(bytes)) {
            result = new String(bytes, StandardCharsets.UTF_8);
        }

        return result;
    }



    /**
     * 功能描述: 数字小的在前面，数字大的在后面
     *
     * @param allColumns allColumns
     * @return java.util.List<com.boman.domain.GenTableColumn>
     */
    public static List<GenTableColumn> filterHrAndSort(List<GenTableColumn> allColumns) {
        requireNonNull(allColumns, "columns is empty");
        return allColumns.stream().filter(col -> HR.equalsIgnoreCase(col.getHtmlType()))
                .sorted(Comparator.comparing(GenTableColumn::getSort))
                .collect(Collectors.toList());
    }


    public static List<GenTableColumn> withHr(List<GenTableColumn> columns) {
        requireNonNull(columns, "columns is empty");
        return filter(columns, col -> HR.equalsIgnoreCase(col.getHtmlType()));
    }

    public static List<GenTableColumn> withoutHr(List<GenTableColumn> columns) {
        requireNonNull(columns, "columns is empty");
        return filter(columns, col -> !HR.equalsIgnoreCase(col.getHtmlType()));
    }

    /**
     * varchar(20) => varchar
     *
     * @param columnType 列类型
     * @return 截取后的列类型
     */
    public static String getDbType(String columnType) {
        if (StringUtils.indexOf(columnType, "(") > 0) {
            return StringUtils.substringBefore(columnType, "(");
        } else {
            return columnType;
        }
    }
}