package com.tofly.feesapi.common.dbhelper;

import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tofly.feesapi.common.util.SpringContextHolder;
import com.tofly.feesapi.common.util.XmlUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.data.redis.core.RedisTemplate;

import java.lang.annotation.Annotation;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import static com.tofly.feesapi.common.ControllerConstants.Mapper_Redis_Prix;

/**
 * 分页排序Helper处理类
 */
public class PageSortHelper {

    private static RedisTemplate redisTemplate = SpringContextHolder.getBean("redisTemplate");

    /**
     * 设置page分页排序参数（针对单表查询，MybatisPlus的Page的方式使用）
     */
    public static void setPageSort(Class t, Page page) {
        if (page.orders().stream().count() > 0) {
            //获取Redis缓存的HashMap
            HashMap<String, String> hmRedisMap = getRedisHashMap(t);
            if (hmRedisMap != null) {
                //获取原始传入的page对象中的Item
                OrderItem orderItemSrc = ((OrderItem) page.orders().get(0));

                //动态赋值order属性
                List<OrderItem> listOrderItem = new ArrayList<>();
                OrderItem orderItem = new OrderItem();
                orderItem.setColumn(hmRedisMap.get(orderItemSrc.getColumn()));
                orderItem.setAsc(orderItemSrc.isAsc());
                listOrderItem.add(orderItem);
                page.setOrders(listOrderItem);
            }
        }
    }

    /**
     * 设置分页排序参数（针对单表查询，DbHelper的方式使用）
     *
     * @param t         实体对象
     * @param strColumn 字段名
     * @param strSort   排序方式：asc、desc
     * @return 数据库order by 后语句：[字段名] [asc/desc]
     */
    public static String setPageSort(Class t, String strColumn, String strSort) {
        if (StringUtils.isBlank(strColumn)) {
            return "";
        }
        String strOrderSort;
        //获取Redis缓存的HashMap
        HashMap<String, String> hmRedisMap = getRedisHashMap(t);
        if (hmRedisMap != null) {
            strOrderSort = MessageFormat.format("{0} {1}", hmRedisMap.get(strColumn), strSort);
        } else {
            strOrderSort = MessageFormat.format("{0} {1}", strColumn, strSort);
        }
        return strOrderSort;
    }

    /**
     * 设置分页排序参数（针对多表查询，MybatisPlus或DbHelper都适用）
     *
     * @param strColumn         排序的字段名
     * @param strSort           排序方式：asc、desc
     * @param arrExcludeColumns 排除的自定义字段，如果定义了此值，则p_strColumn与子项相同时会优先使用
     * @return 数据库order by 后语句：[字段名] [asc/desc]
     */
    public static String setPageSort(String strColumn, String strSort, String[] arrExcludeColumns) {
        if (StringUtils.isBlank(strColumn)) {
            return "";
        }
        String strOrderSort = "";
        if (arrExcludeColumns != null) {
            //判断动态传入的列名是否含有需要排除的自定义列
            for (String strExcColumn : arrExcludeColumns) {
                if (StringUtils.isBlank(strExcColumn)) {
                    continue;
                }
                if (strExcColumn.equalsIgnoreCase(strColumn)) {
                    strOrderSort = MessageFormat.format("\"{0}\" {1}", strExcColumn, strSort);
                    break;
                }
            }
        }
        if (StringUtils.isBlank(strOrderSort)) {
            //对传入的列名进行排序处理，从“驼峰命名”转为”大写的下划线分隔“，如：userName >> USER_NAME
            StringBuilder sbTemp = new StringBuilder();
            String[] arrColumns = strColumn.split("");
            for (String sColumn : arrColumns) {
                if (sColumn.equals(sColumn.toUpperCase())) {
                    sbTemp.append("_");
                }
                sbTemp.append(sColumn);
            }
            strOrderSort = MessageFormat.format("{0} {1}", sbTemp.toString(), strSort);
        }
        return strOrderSort;
    }

    /**
     * 设置分页排序参数（针对多表查询，MybatisPlus适用）
     *
     * @param page              分页对象
     * @param arrExcludeColumns 排除的自定义字段，如果定义了此值，则page.orders中的column与子项相同时会优先使用
     */
    public static void setPageSort(Page page, String[] arrExcludeColumns) {
        if (page.orders().stream().count() > 0) {
            //获取原始传入的page对象中的Item
            OrderItem orderItemSrc = ((OrderItem) page.orders().get(0));
            String strColumn = orderItemSrc.getColumn();

            boolean isFlag = false;
            if (arrExcludeColumns != null) {
                //判断动态传入的列名是否含有需要排除的自定义列
                for (String strExcColumn : arrExcludeColumns) {
                    if (StringUtils.isBlank(strExcColumn)) {
                        continue;
                    }
                    if (strExcColumn.equalsIgnoreCase(strColumn)) {
                        strColumn = MessageFormat.format("\"{0}\"", strExcColumn);
                        isFlag = true;
                        break;
                    }
                }
            }
            if (!isFlag) {
                //对传入的列名进行排序处理，从“驼峰命名”转为”大写的下划线分隔“，如：userName >> USER_NAME
                StringBuilder sbTemp = new StringBuilder();
                String[] arrColumns = strColumn.split("");
                for (String sColumn : arrColumns) {
                    if (sColumn.equals(sColumn.toUpperCase())) {
                        sbTemp.append("_");
                    }
                    sbTemp.append(sColumn);
                }
                strColumn=sbTemp.toString();
            }
            //动态赋值order属性
            List<OrderItem> listOrderItem = new ArrayList<>();
            OrderItem orderItem = new OrderItem();
            orderItem.setColumn(strColumn);
            orderItem.setAsc(orderItemSrc.isAsc());
            listOrderItem.add(orderItem);
            page.setOrders(listOrderItem);
        }
    }
    //endregion

    //region 内部方法
    /**
     * 获取泛型实体类对应的Mapper文件路径
     *
     * @param t 实体类
     * @return Mapper文件路径
     */
    private static String getMapperPath(Class t) {
        String strProjectName = "fees";
        String strNamespace = t.getName();
        strNamespace = strNamespace.substring(strNamespace.indexOf(strProjectName) + strProjectName.length() + 1);
        strNamespace = strNamespace.substring(0, strNamespace.indexOf("."));
        String strClassName = t.getSimpleName();
        return MessageFormat.format("{0}/{1}mapper.xml", strNamespace, strClassName);
    }

    /**
     * 通过泛型实体类获取Mapper文件中的数据库对应关系，存储至redis中
     *
     * @param t 泛型实体类
     * @return Mapper文件路径
     */
    private static HashMap<String, String> getRedisHashMap(Class t) {
        String strMapperPath = getMapperPath(t);
        String strMapperId = ((TableName) getTableNameAnnotation(t)).resultMap();

        String strCacheKey = Mapper_Redis_Prix + strMapperId;
        HashMap<String, String> es = (HashMap<String, String>) redisTemplate.opsForValue().get(strCacheKey);
        if (es == null) {
            es = XmlUtils.getHashMapperColumnByElement(strMapperPath, strMapperId);
            redisTemplate.opsForValue().set(strCacheKey, es);
        }
        return es;
    }

    /**
     * 获取泛型实体类对应的TableName注解对象
     *
     * @param t 泛型实体类
     * @return 实体类对应的TableName注解对象
     */
    private static Annotation getTableNameAnnotation(Class t) {
        Annotation[] annotations = t.getDeclaredAnnotations();
        for (Annotation annotation : annotations) {
            if (annotation instanceof TableName) {
                return annotation;
            }
        }
        return null;
    }
    //endregion
}
