package cn.estsh.i3plus.pojo.base.tool;

import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.Block;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.Sorts;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.data.mongodb.core.MongoOperations;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;

/**
 * @Description :
 * @Reference :
 * @Author : alwaysfrin
 * @CreateDate : 2018-11-01 16:26
 * @Modify:
 *
 * (>) 大于 - $gt
 * (<) 小于 - $lt
 * (>=) 大于等于 - $gte
 * (<= ) 小于等于 - $lte
 *  $ne ----------- not equal  !=
 *   $eq  --------  equal  =
 *
 *   查询 title 包含"库"字的文档：
 *   db.col.find({title:/库/})
 *
 *   查询 title 字段以"教"字开头的文档：
 *   db.col.find({title:/^库/})
 *
 *   查询 titl e字段以"教"字结尾的文档：
 *   db.col.find({title:/库$/})
 **/
public class BsonPackTool {

    /**
     * 防止sql注入
     * @param data
     * @return
     */
    public static String getSafeParam(Object data){
        return data.toString().replaceAll(";","")
                .replaceAll("'","")
                .replaceAll("\"","")
                .replaceAll("/","")
                .replaceAll("\\\\","")
                .replaceAll("delete","")
                .replaceAll("update","")
                .replaceAll("insert","");
    }

    /**
     * 单页查询，获取查询document结果集合
     * @param mongoOperations
     * @param tableName 查询的表名
     * @param bson 查询条件
     * @param skip 忽略的条数
     * @param limit 查询的条数
     * @return document结果集合
     */
    public static List<Document> query(MongoOperations mongoOperations, String tableName, Bson bson, int skip, int limit) {
        List<Document> newLins = new ArrayList<>();
        Block<Document> saveBlock = new Block<Document>() {
            @Override
            public void apply(final Document document) {
                newLins.add(document);
            }
        };

        //查询
        MongoCollection<Document> collection = mongoOperations.getCollection(tableName);
        if(bson == null) {
            collection.count();
            collection.find().skip(skip).limit(limit).forEach(saveBlock);
        }else {
            collection.count(bson);
            collection.find(bson).skip(skip).limit(limit).forEach(saveBlock);
        }

        return newLins;
    }

    /**
     * 分页查询
     * @param mongoOperations
     * @param tableName 表名
     * @param bson 查询条件
     * @param pageSize 单页查询条数
     * @return 查询结果集合
     */
    public static List<Document> queryPages(MongoOperations mongoOperations, String tableName, Bson bson, int pageSize) {
        //分页查询
        List<Document> list = new ArrayList<>();
        long count = mongoOperations.getCollection(tableName).count(bson);
        int loops = (int)((count + pageSize - 1) / pageSize);
        List<Document> newFinds = null;
        for(int i = 0; i < loops; i++) {
            newFinds = query(mongoOperations, tableName, bson, i * pageSize, pageSize);
            list.addAll(newFinds);
        }
        return list;
    }

    /**
     * 封装日期
     * @param startDate 开始日期
     * @param endDate 开始日期和结束日期，以逗号分隔（分为开始时间和结束时间）
     * @param columnName HQL里对应的时间字段
     * @param bson 封装的bson
     * @param isShowTime 是否包含时分秒
     */
    public static Bson timeBuilder( String startDate,String endDate, String columnName, Bson bson, boolean isShowTime) {
        if (startDate == null || startDate.trim().length() == 0) {
            startDate = "1900-01-01";
        } else {
            startDate = getSafeParam(startDate);
            startDate = startDate.trim();
        }
        if (isShowTime && startDate.trim().length()<=11) {
            startDate+= " 00:00:00";
        }
        if (endDate == null || endDate.trim().length() == 0) {
            endDate = "2100-01-01";
        } else {
            endDate = getSafeParam(endDate);
            endDate = endDate.trim();
        }
        if (isShowTime&& endDate.trim().length()<=11) {
            endDate+= " 23:59:59";
        }
        if(bson == null) {
            bson = Filters.and(
                    Filters.gte(columnName, startDate),  //大于等于开始日期
                    Filters.lte(columnName, endDate)     //小于等于结束日期
            );
        }else{
            bson = Filters.and(
                    bson,
                    Filters.gte(columnName, startDate),  //大于等于开始日期
                    Filters.lte(columnName, endDate)     //小于等于结束日期
            );
        }

        return bson;
    }

    /**
     * 封装日期
     * @param date 开始日期和结束日期，以逗号分隔（分为开始时间和结束时间）
     * @param columnName HQL里对应的时间字段
     * @param bson 封装的bson
     * @param showToday 如果没有开始时间和结束时间，是否查询当天时间，还是查询所有时间。true:查询当天时间，false:查询所有
     * @param isShowTime 是否包含时分秒
     */
    public static Bson timeBuilder( String date, String columnName, Bson bson, boolean showToday,boolean isShowTime) {
        if(date != null && !"null".equals(date) && date.trim().length() > 0){
            date = getSafeParam(date);

            String today = (new SimpleDateFormat("yyyy-MM-dd")).format(new Date());
            if(date.length() == 1 || ",".equals(date)){
                //只有一个逗号
                date = "";
            }

            String[] time = date.split(",");
            if(time.length == 1){
                //只有开始日期，没有结束日期
                if(bson == null){
                    bson = Filters.and(
                            Filters.regex(columnName, "^" + time[0]) //like 日期%^
                    );
                }else {
                    bson = Filters.and(
                            bson,
                            Filters.regex(columnName, "^" + time[0]) //like 日期%^
                    );
                }
            }else if (time.length == 2 && ((time[0] != null && time[0].trim().length() > 0) || (time[1] != null & time[1].trim().length() > 0))) {
                if (time[0] == null || time[0].trim().length() == 0) {
                    time[0] = "1900-01-01";
                } else {
                    time[0] = time[0].trim();
                }
                if (isShowTime && time[0].trim().length()<=11) {
                    time[0]+= " 00:00:00";
                }
                if (time[1] == null || time[1].trim().length() == 0) {
                    time[1] = "2100-01-01";
                } else {
                    time[1] = time[1].trim();
                }
                if (isShowTime&& time[1].trim().length()<=11) {
                    time[1]+= " 23:59:59";
                }
                if(bson == null) {
                    bson = Filters.and(
                            Filters.gte(columnName, time[0]),  //大于等于开始日期
                            Filters.lte(columnName, time[1])     //小于等于结束日期
                    );
                }else{
                    bson = Filters.and(
                            bson,
                            Filters.gte(columnName, time[0]),  //大于等于开始日期
                            Filters.lte(columnName, time[1])     //小于等于结束日期
                    );
                }
            } else {
                if (showToday) {
                    if (isShowTime) {
                        if(bson == null) {
                            bson = Filters.and(
                                    Filters.gte(columnName, time[0] + " 00:00:00"),  //大于等于开始日期
                                    Filters.lte(columnName, time[1] + " 23:59:59")     //小于等于结束日期
                            );
                        }else{
                            bson = Filters.and(
                                    bson,
                                    Filters.gte(columnName, time[0] + " 00:00:00"),  //大于等于开始日期
                                    Filters.lte(columnName, time[1] + " 23:59:59")     //小于等于结束日期
                            );
                        }
                    }else{
                        if(bson == null) {
                            bson = Filters.and(
                                    Filters.gte(columnName, time[0]),  //大于等于开始日期
                                    Filters.lte(columnName, time[1])     //小于等于结束日期
                            );
                        }else{
                            bson = Filters.and(
                                    bson,
                                    Filters.gte(columnName, time[0]),  //大于等于开始日期
                                    Filters.lte(columnName, time[1])     //小于等于结束日期
                            );
                        }
                    }
                }
            }
        }
        return bson;
    }

    /**
     * 查询方位分装
     * @param columnName    列名称
     * @param bson
     * @param startTime     开始值
     * @param endTime       结束之
     * @return
     */
    public static Bson timeBuilder(String columnName, Bson bson, String startTime,String endTime) {
        if( Objects.nonNull(bson) && StringUtils.isNotBlank(columnName) &&StringUtils.isNotBlank(startTime)&& StringUtils.isNotBlank(endTime)){
            bson = Filters.and(
                    bson,
                    Filters.gte(columnName, startTime),  //大于等于开始日期
                    Filters.lte(columnName, endTime)     //小于等于结束日期
            );
        }
        return bson;
    }

    /**
     * 大于日期
     * @param dateTime 日期
     * @param columnName HQL里对应的时间字段
     * @param bson 封装的bson
     * @param isShowTime 是否包含时分秒
     */
    public static Bson timeMore( String dateTime, String columnName, Bson bson, boolean isShowTime) {
        if (dateTime == null || dateTime.trim().length() == 0) {
            dateTime = "1900-01-01";
        } else {
            dateTime = getSafeParam(dateTime);
            dateTime = dateTime.trim();
        }
        if (isShowTime && dateTime.trim().length()<=11) {
            dateTime+= " 00:00:00";
        }
        if(bson == null) {
            bson = Filters.and(
                    Filters.gte(columnName, dateTime)  //大于等于开始日期
            );
        }else{
            bson = Filters.and(
                    bson,
                    Filters.gte(columnName, dateTime)  //大于等于开始日期
            );
        }

        return bson;
    }

    /**
     * 小于日期
     * @param dateTime 日期
     * @param columnName HQL里对应的时间字段
     * @param bson 封装的bson
     * @param isShowTime 是否包含时分秒
     */
    public static Bson timeLess( String dateTime, String columnName, Bson bson, boolean isShowTime) {
        if (dateTime == null || dateTime.trim().length() == 0) {
            dateTime = "2100-01-01";
        } else {
            dateTime = getSafeParam(dateTime);
            dateTime = dateTime.trim();
        }
        if (isShowTime&& dateTime.trim().length()<=11) {
            dateTime+= " 23:59:59";
        }
        if(bson == null) {
            bson = Filters.and(
                    Filters.lte(columnName, dateTime)     //小于等于结束日期
            );
        }else{
            bson = Filters.and(
                    bson,
                    Filters.lte(columnName, dateTime)     //小于等于结束日期
            );
        }

        return bson;
    }

    /**
     * 封装String对象成like语句
     * @param str 对象值
     * @param columnName 列名
     * @param bson
     */
    public static Bson getStringLikerPack(String str,String columnName, Bson bson) {
        if (str != null && str.trim().length() > 0) {
            str = getSafeParam(str);

            if(bson == null) {
                bson = Filters.and(
                        Filters.regex(columnName, str) //like
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.regex(columnName, str)//like
                );
            }
        }

        return bson;
    }

    /**
     * 封装String对象成like语句
     * @param str 对象值
     * @param columnName 列名
     * @param bson
     */
    public static Bson getStringLikerPackOr(String str,String columnName, Bson bson) {
        if (str != null && str.trim().length() > 0) {
            str = getSafeParam(str);

            if(bson == null) {
                bson = Filters.or(
                               Filters.regex(columnName, str) //like
                        );
            }else {
                bson = Filters.and(
                        bson,
                        Filters.or(
                                Filters.regex(columnName, str) //like
                        )
                );
            }
        }
        return bson;
    }

    /**
     * 封装String对象成like语句(右侧模糊)
     * @param str 对象值
     * @param columnName 列名
     * @param bson
     */
    public static Bson getStringRightLikerPack(String str,String columnName, Bson bson) {
        if (str != null && str.trim().length() > 0) {
            str = getSafeParam(str);
            if(bson == null) {
                bson = Filters.and(
                        Filters.regex(columnName, str + "^") //like
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.regex(columnName, str + "^") //like
                );
            }
        }
        return bson;
    }

    /**
     * 封装String对象成like语句(左侧模糊)
     * @param str 对象值
     * @param columnName 列名
     * @param bson
     */
    public static Bson getStringLeftLikerPack(String str,String columnName, Bson bson) {
        if (str != null && str.trim().length() > 0) {
            str = getSafeParam(str);
            if(bson == null) {
                bson = Filters.and(
                        Filters.regex(columnName, "^" + str) //like
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.regex(columnName, "^" + str) //like
                );
            }
        }
        return bson;
    }

    /**
     * 封装String对象成equal语句
     * @param columnName 列名
     * @param bson
     */
    public static Bson getStringEqualPack(String data,String columnName, Bson bson) {
        if(data != null && data.trim().length() > 0){
            data = getSafeParam(data);
            if(bson == null) {
                bson = Filters.and(
                        Filters.eq(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.eq(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 封装long或者int的整数对象成equal语句
     * @param columnName 列名
     * @param bson
     */
    public static Bson getNumEqualPack(Object data,String columnName, Bson bson) {
        if(data!=null&&Long.parseLong(data.toString()) > 0){
            if(bson == null) {
                bson = Filters.and(
                        Filters.eq(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.eq(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 封装long或者int的整数对象成equal语句
     * @param columnName 列名
     * @param bson
     */
    public static Bson getNumEqualPackForZero(Object data,String columnName, Bson bson) {
        if(data!=null&&Long.parseLong(data.toString()) >= 0){
            if(bson == null) {
                bson = Filters.and(
                        Filters.eq(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.eq(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 封装long或者int的整数对象成equal语句
     * @param columnName 列名
     * @param bson
     */
    public static Bson getNumWithZeroEqualPack(Object data,String columnName, Bson bson) {
        if(data!=null&&Long.parseLong(data.toString()) >= 0){
            if(bson == null) {
                bson = Filters.and(
                        Filters.eq(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.eq(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 封装long或者int的整数对象成大于语句
     * @param columnName 列名
     * @param bson
     */
    public static Bson getNumBiggerPack(Object data,String columnName, Bson bson) {
        if(data!=null&&Long.parseLong(data.toString()) > 0){
            if(bson == null) {
                bson = Filters.and(
                        Filters.gt(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.gt(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 封装long或者int的整数对象成小于语句
     * @param columnName 列名
     * @param bson
     */
    public static Bson getNumSmallerPack(Object data,String columnName, Bson bson) {
        if(data!=null&&Long.parseLong(data.toString()) > 0){
            if(bson == null) {
                bson = Filters.and(
                        Filters.lt(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.lt(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 封装double对象成大于语句
     * @param columnName 列名
     * @param bson
     */
    public static Bson getDoubleBiggerPack(Object data,String columnName, Bson bson) {
        if(data!=null&&Double.parseDouble(data.toString()) > 0){
            if(bson == null) {
                bson = Filters.and(
                        Filters.gt(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.gt(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 封装double对象成小于语句
     * @param columnName 列名
     * @param bson
     */
    public static Bson getDoubleSmallerPack(Object data,String columnName, Bson bson) {
        if(data!=null&&Double.parseDouble(data.toString()) > 0){
            if(bson == null) {
                bson = Filters.and(
                        Filters.lt(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.lt(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 封装long或者int的整数对象成equal语句
     * @param columnName 列名
     * @param bson
     */
    public static Bson getNumEqualPack(Object data,String columnName, Bson bson,Integer expvalue) {
        if(data!=null&&Long.parseLong(data.toString()) > (long)expvalue){
            if(bson == null) {
                bson = Filters.and(
                        Filters.eq(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.eq(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 封装double对象成equal语句
     * @param columnName 列名
     * @param bson
     */
    public static Bson getNumEqualPackDouble(Object data,String columnName, Bson bson) {
        if(data!=null&&Double.parseDouble(data.toString()) > 0){
            if(bson == null) {
                bson = Filters.and(
                        Filters.eq(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.eq(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 封装long或者int的整数对象成equal语句
     * @param columnName 列名
     * @param bson
     */
    public static Bson getNumEqualPackDouble(Object data,String columnName, Bson bson,Integer expvalue) {
        if(data!=null&&Double.parseDouble(data.toString()) > (double)expvalue){
            if(bson == null) {
                bson = Filters.and(
                        Filters.eq(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.eq(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 封装long或者int的整数对象成equal语句(不等于)
     * @param columnName 列名
     * @param bson
     */
    public static Bson getNumNOEqualPack(Object data,String columnName, Bson bson) {
        if(data!=null){
            if(bson == null) {
                bson = Filters.and(
                        Filters.ne(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.ne(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 封装in查询语句
     * @param data
     * @param columnName
     * @param bson
     */
    public static Bson getInPack(String data,String columnName, Bson bson){
        if (data!=null&&data.trim().length()>0) {
            data = getSafeParam(data);
            if(bson == null) {
                bson = Filters.and(
                        Filters.in(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.in(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 封装in String查询语句
     * @param data
     * @param columnName
     * @param bson
     */
    public static Bson getInPackString(String data,String columnName, Bson bson){
        if (data != null && data.trim().length()>0) {
            data = getSafeParam(data);
            //判断最后一位是不是逗号
            if(data.lastIndexOf(",") != (data.length()-1)){
                data += ",";
            }
            String[] dataArray = data.substring(0, data.length()-1).split(",");
            data = "";
            for (int i = 0 ; i < dataArray.length ;i++) {
                if(i ==  dataArray.length -1){
                    data += "'" + dataArray[i] + "'";
                }else{
                    data += "'" + dataArray[i] + "',";
                }
            }
            if(bson == null) {
                bson = Filters.and(
                        Filters.in(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.in(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 封装in String查询语句
     * @param data
     * @param columnName
     * @param bson
     */
    public static Bson getNotInPackString(String data,String columnName, Bson bson){
        if (data != null && data.trim().length()>0) {
            data = getSafeParam(data);
            //判断最后一位是不是逗号
            if(data.lastIndexOf(",") != (data.length()-1)){
                data += ",";
            }
            String[] dataArray = data.substring(0, data.length()-1).split(",");
            data = "";
            for (int i = 0 ; i < dataArray.length ;i++) {
                if(i ==  dataArray.length -1){
                    data += "'" + dataArray[i] + "'";
                }else{
                    data += "'" + dataArray[i] + "',";
                }
            }
            if(bson == null) {
                bson = Filters.and(
                        Filters.nin(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.nin(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 封装not in查询语句
     * @param data
     * @param columnName
     * @param bson
     */
    public static Bson getNotInPack(String data,String columnName, Bson bson){
        if (data!=null&&data.trim().length()>0) {
            data = getSafeParam(data);
            if(bson == null) {
                bson = Filters.and(
                        Filters.nin(columnName, data)
                );
            }else{
                bson = Filters.and(
                        bson,
                        Filters.nin(columnName, data)
                );
            }
        }
        return bson;
    }

    /**
     * 将MONGODB的BSON转成对象
     * @param dList
     * @param entityClass
     * @return
     */
    public List<?> packDocumentToObjectList(List<Document> dList,Class entityClass){
        //将获取的document转为对象
        List resultList = new ArrayList();
        for(Document d : dList){
            resultList.add(JSONObject.parseObject(d.toJson(), entityClass));
        }

        return resultList;
    }
}
