package com.yeejoin.amos.knowledgebase.face.util;

import com.alibaba.fastjson.JSON;
import com.yeejoin.amos.knowledgebase.face.model.KnowledgeTagInstanceModel;
import com.yeejoin.amos.knowledgebase.face.model.KnowledgeTagValueModel;
import com.yeejoin.amos.knowledgebase.face.service.TagValueService;
import lombok.Data;
import org.typroject.tyboot.core.foundation.exception.BaseException;
import org.typroject.tyboot.core.foundation.utils.Bean;
import org.typroject.tyboot.core.foundation.utils.DateUtil;
import org.typroject.tyboot.core.foundation.utils.ValidationUtil;
import org.typroject.tyboot.core.restful.exception.instance.BadRequest;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

/**
 * 文档根据标签定制化排序
 *
 * @author tiantao
 */
public class DocSortUtil {

    public static List<DocTagConfig> tagConfigList;

    /**
     * 正数恒定大于负数，1开头表正数，0开头表负数
     */
    private static final String POSITIVE = "1";
    private static final String NEGATIVE = "0";
    private static final DecimalFormat LONG_FORMAT = new DecimalFormat("0000000000000000000");

    static {
        loadConfig();
    }

    public static void loadConfig() {
        Object configObj = JSON.parse("{\n" +
                "  \"docTag\": [\n" +
                "    {\n" +
                "      \"sort\": 1,\n" +
                "      \"name\": \"死亡/失踪人数总和\",\n" +
                "      \"desc\": true,\n" +
                "      \"formula\": \"1319951584694317058+1319952328386359297+1319951672883752961+1319952397084864513\"\n" +
                "    },\n" +
                "    {\n" +
                "      \"sort\": 2,\n" +
                "      \"name\": \"受伤人数总和\",\n" +
                "      \"desc\": true,\n" +
                "      \"formula\": \"1319951506357301249+1319952269997453314+1319951885195227138+1319952474897592321\"\n" +
                "    },\n" +
                "    {\n" +
                "      \"sort\": 3,\n" +
                "      \"name\": \"参战总人数\",\n" +
                "      \"desc\": true,\n" +
                "      \"formula\": \"1319953830182072322\"\n" +
                "    },\n" +
                "    {\n" +
                "      \"sort\": 4,\n" +
                "      \"name\": \"处置时间\",\n" +
                "      \"desc\": true,\n" +
                "      \"formula\": \"1320181702299004930-1320181277285986305\"\n" +
                "    }\n" +
                "  ]\n" +
                "}");
        tagConfigList = new ArrayList<>();
        if (configObj instanceof Map) {
            Object docTag = ((Map) configObj).get("docTag");
            if (docTag instanceof List) {
                ((List) docTag).forEach(tag -> {
                    try {
                        DocTagConfig docTagConfig = JSON.parseObject(JSON.toJSONString(tag), DocTagConfig.class);
                        tagConfigList.add(docTagConfig);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
            }
        }
        tagConfigList.sort(Comparator.comparingInt(o -> o.sort));
    }

    public static String getSortStr(List<KnowledgeTagInstanceModel> docTags) {
        Map<Object, KnowledgeTagInstanceModel> docTagsMap = Bean.listToMap(docTags, "tagSeq", KnowledgeTagInstanceModel.class);
        StringBuilder res = new StringBuilder();
        final boolean[] flag = {false};
        tagConfigList.forEach(docTagConfig -> {
            String formula = docTagConfig.formula;
            List<String> tagSeqs = trimArray(formula.split("\\D"));
            long sortValue = 0L;
            for (int i = 0; i < tagSeqs.size(); i++) {
                Long tagValue = getTagLongValue(tagSeqs.get(i), docTagsMap);
                if (i > 0) {
                    String operator = formula.substring(formula.indexOf(tagSeqs.get(i - 1)) + tagSeqs.get(i - 1).length(), formula.indexOf(tagSeqs.get(i)));
                    switch (operator.trim()) {
                        case "+":
                            sortValue += tagValue;
                            break;
                        case "-":
                            sortValue -= tagValue;
                            break;
                        default:
                            throw new BadRequest("排序规则错误，无法识别的运算符");
                    }
                } else {
                    sortValue = tagValue;
                }
            }
            if (flag[0]) {
                res.append("_");
            }else {
                flag[0] = true;
            }
            res.append(formatLong2SortStr(sortValue, docTagConfig.desc));
        });
        return res.toString();
    }

    /**
     * 依据正负数/正倒序转换数值为字符串正整数
     * @param sortValue 数值
     * @param desc 是否倒序排列
     * @return 字符串
     */
    private static String formatLong2SortStr(long sortValue, boolean desc) {
        if (desc) {
            if (sortValue < 0) {
                sortValue = 0 - sortValue;
                return POSITIVE + LONG_FORMAT.format(sortValue);
            } else {
                sortValue = Long.MAX_VALUE - sortValue;
                return NEGATIVE + LONG_FORMAT.format(sortValue);
            }
        } else {
            if (sortValue < 0) {
                sortValue = Long.MAX_VALUE - (0 - sortValue);
                return NEGATIVE + LONG_FORMAT.format(sortValue);
            } else {
                return POSITIVE + LONG_FORMAT.format(sortValue);
            }
        }
    }

    /**
     * 获取不同数据格式转化的long数值
     * @param ts 标签实例id
     * @param docTagsMap 标签实例map
     * @return long值
     */
    private static Long getTagLongValue(String ts, Map<Object, KnowledgeTagInstanceModel> docTagsMap) {
        Long res = 0L;
        try {
            Long tagSeq = Long.valueOf(ts.trim());
            KnowledgeTagInstanceModel instanceModel = docTagsMap.get(tagSeq);
            if (null == instanceModel) {
                return res;
            }
            List<KnowledgeTagValueModel> tagValues = instanceModel.getTagValues();
            if (tagValues != null && tagValues.size() > 0) {
                String fieldName = tagValues.get(0).getFieldName();
                String tagValue = tagValues.get(0).getTagValue();
                switch (fieldName) {
                    case TagValueService.VALUE_TAG_FIELD_DATE_H:
                        res = DateUtil.formatStringToDate(tagValue, null).getTime();
                        break;
                    case TagValueService.VALUE_TAG_FIELD_SINGLEVALUE:
                        res = Long.valueOf(tagValue);
                        break;
                    default:
                        throw new BadRequest("排序规则错误，不支持的数据类型");
                }
            }
        } catch (BaseException e) {
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return res;
    }


    /**
     * 去除数组中的空值
     * @param arr 数组
     * @param <T> 泛型
     * @return List
     */
    private static <T> List<T> trimArray(T[] arr) {
        List<T> res = new ArrayList<>();
        for (T t : arr) {
            if (!ValidationUtil.isEmpty(t)) {
                res.add(t);
            }
        }
        return res;
    }

    @Data
    private static class DocTagConfig {
        // 排序优先级
        private int sort;
        // 排序名称，方便读懂json与逻辑无关
        private String name;
        // 是否倒序
        private boolean desc;
        // 算法公式，格式为标签id用数学运算符连接，目前仅支持加减
        private String formula;
    }
}
