package com.org.hktshop.base;


import com.org.hktshop.entity.Page;
import com.org.hktshop.entity.vo.HktGoodItemXcx;
import com.org.hktshop.entity.vo.HktGoodsAttrItemXcx;
import com.org.hktshop.target01.TableField;
import com.org.hktshop.utils.ClassUtil;
import com.org.hktshop.utils.ClassUtils;
import com.org.hktshop.utils.StringUtils;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;

import java.lang.reflect.*;
import java.util.*;
import java.util.stream.Collectors;

import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;

@Component
public class MongoHelper<T extends BaseModel> {

    //反射为属性方法 获取value
    private static String getMethodName(String fildeName) throws Exception {
        byte[] items = fildeName.getBytes();
        items[0] = (byte) ((char) items[0] - 'a' + 'A');
        return new String(items);
    }

    public Query createQuery(T inEntity, Class<T> clazz) {
        ArrayList<Criteria> list = new ArrayList<>();

        //获取查询字段
        List<Field> MyFiles = ClassUtils.getSelfBeanInfo(clazz);
        for (Field fd : MyFiles) {
            TableField annotation = fd.getAnnotation(TableField.class);
            if (annotation == null) continue;

            if (StringUtils.isNull(annotation.value())) continue;

            String Value = fd.getName();
            if (StringUtils.isNull(Value)) continue;

            Object p = null;
            try {
                Method m = (Method) clazz.getMethod(
                        "get" + getMethodName(fd.getName()));
                p = m.invoke(inEntity);// 调用getter方法获取属性值
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (!StringUtils.isNull(p)) {
                Criteria criteria = Criteria.where(Value).is(p);
                list.add(criteria);
            }
        }
        Query query;
        if (list.size() > 0) {
            Criteria[] arr = new Criteria[list.size()];
            list.toArray(arr);
            Criteria criteria = new Criteria().andOperator(arr);
            query = new Query(criteria);
        } else {
            query = new Query();
        }
        return query;
    }

    /**
     * spring mongodb　集成操作类
     *
     * @author tw
     * @deprecated 我怎么在这里生成不了对象，mongoTemplate 为null
     */
    public static MongoTemplate mongoTemplate;

    public static void InitMongoDb(MongoTemplate iNmongoTemplate) {
        mongoTemplate = iNmongoTemplate;
    }


    /**
     * 通过条件查询实体(集合)
     *
     * @param
     */

    public List<T> find(T inEntity, Class<T> clazz) {
        Query query = createQuery(inEntity, clazz);
        return mongoTemplate.find(query, clazz);
    }

    public List<T> find(Query query, Class<T> clazz) {
        return mongoTemplate.find(query, clazz);
    }

    public List<T> find(T inEntity, Class<T> clazz, String collectionName) {
        Query query = createQuery(inEntity, clazz);
        return mongoTemplate.find(query, clazz, collectionName);
    }

    public List<T> find(Query query, Class<T> clazz, String collectionName) {
        return mongoTemplate.find(query, clazz, collectionName);
    }

    public List<T> findIn(String key, Object[] arr, Class<T> tClass) {
        Query query = new Query(Criteria.where(key).in(arr));
        return mongoTemplate.find(query, tClass);
    }

    /**
     * 通过一定的条件查询一个实体
     *
     * @param
     * @return
     */
    public T findOne(T inEntity, Class<T> clazz) {

        Query query = createQuery(inEntity, clazz);
        return mongoTemplate.findOne(query, clazz);
    }

    public T findOne(Query query, Class<T> clazz,String collectionName) {
        return mongoTemplate.findOne(query, clazz, collectionName);
    }

    public T findOne(T inEntity, String collectionName, Class<T> clazz) {
        Query query = createQuery(inEntity, clazz);
        return mongoTemplate.findOne(query, clazz, collectionName);
    }
    public T findOne(Query query, Class<T> clazz) {
        return mongoTemplate.findOne(query, clazz);
    }

    /**
     * 通过条件查询更新数据
     *
     * @return
     */
//    public void update(Query query, Update update) {
//        mongoTemplate.findAndModify(query, update, this.getEntityClass());
//    }
//
//    public void update(Query query, Update update, String collectionName) {
//        mongoTemplate.findAndModify(query, update, this.getEntityClass(), collectionName);
//    }
    public void removeById(String id, String collectionName) {
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        mongoTemplate.remove(query, collectionName);
    }

    public void removeById(String id, Class<T> tClass) {
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        mongoTemplate.remove(query, tClass);
    }

    /**
     * 保存一个对象到mongodb
     *
     * @param entity
     * @return
     */
    public T save(T entity) {
        mongoTemplate.insert(entity);
        return entity;
    }

    public T save(T entity, String collectionName) {
        mongoTemplate.insert(entity, collectionName);
        return entity;
    }

    /***
     *
     * @param entity
     * @return
     */
    public void save(List<T> entity) {
        mongoTemplate.insertAll(entity);
    }

    /**
     * 分页查询
     *
     * @return
     */
    public Page<T> findPage(T inEntity, Class<T> clazz) {

        Query query = createQuery(inEntity, clazz);
        Page<T> page = new Page<>();

        long count = this.count(query, clazz);
        page.setTotal(count);
        if (inEntity.getPageSize() <= 0 || inEntity.getPageNum() < 1) return page;

        page.setPageSize(inEntity.getPageSize());
        page.setPages(count / inEntity.getPageSize() + 1);
        long pageNumber = inEntity.getPageNum();
        int pageSize = inEntity.getPageSize();
        query.skip((pageNumber - 1) * pageSize).limit(pageSize);
        List<T> rows = this.find(query, clazz);
        page.setRecords(rows);
        return page;
    }

    /**
     * 分页查询
     *
     * @return
     */
    public Page<T> findPage(T inEntity, Class<T> clazz, String collectionName) {

        Query query = createQuery(inEntity, clazz);
        Page<T> page = new Page<>();

        long count = this.count(query, clazz, collectionName);
        page.setTotal(count);
        if (inEntity.getPageSize() <= 0 || inEntity.getPageNum() < 1) return page;

        page.setPageSize(inEntity.getPageSize());
        page.setPages(count / inEntity.getPageSize() + 1);
        long pageNumber = inEntity.getPageNum();
        int pageSize = inEntity.getPageSize();
        query.skip((pageNumber - 1) * pageSize).limit(pageSize);
        List<T> rows = this.find(query, clazz, collectionName);
        page.setRecords(rows);
        return page;
    }

    public Page<T> findPage(T entity, Query query, Class<T> clazz) {

        Page<T> page = new Page<>();
        long count = this.count(query, clazz);
        page.setTotal(count);
        if (StringUtils.isNull(entity.getPageSize())) entity.setPageSize(20);
        if (StringUtils.isNull(entity.getPageNum())) entity.setPageNum(1);
        if (entity.getPageSize() <= 0 || entity.getPageNum() < 1) return page;
        int pageNumber = entity.getPageNum();
        int pageSize = entity.getPageSize();
        page.setPages(count / pageSize + 1);
        query.skip((pageNumber - 1) * pageSize).limit(pageSize);
        List<T> rows = this.find(query, clazz);
        page.setRecords(rows);
        return page;
    }


    public Page<T> findPage(T entity, Query query, Class<T> clazz, String collectionName) {
        Page<T> page = new Page<>();
        long count = this.count(query, clazz, collectionName);
        page.setTotal(count);
        if (StringUtils.isNull(entity.getPageSize())) entity.setPageSize(20);
        if (StringUtils.isNull(entity.getPageNum())) entity.setPageNum(1);
        if (entity.getPageSize() <= 0 || entity.getPageNum() < 1) return page;

        int pageNumber = entity.getPageNum();
        int pageSize = entity.getPageSize();
        query.skip((pageNumber - 1) * pageSize).limit(pageSize);
        List<T> rows = this.find(query, clazz, collectionName);
        page.setRecords(rows);
        return page;
    }

    /**
     * 求数据总和
     *
     * @param query
     * @return
     */
    public long count(Query query, Class<T> tClass) {
        return mongoTemplate.count(query, tClass);
    }

    public long count(Query query, Class<T> tClass, String collectionName) {
        return mongoTemplate.count(query, tClass, collectionName);
    }

    /***
     * 删除数据
     * @param query
     * @param tClass
     * @return
     */
    public boolean delete(Query query, Class<T> tClass) {
        mongoTemplate.remove(query, tClass);
        return true;
    }

    public List<String> distinct(Criteria criteria, String field, String collectionName) {

        Aggregation aggregation = Aggregation.newAggregation(
                match(criteria),
                group(field).count().as("pageNum"));
        AggregationResults<BaseModel> outputTypeCount = mongoTemplate.aggregate(aggregation, collectionName, BaseModel.class);

        List<String> list = new ArrayList<>();
        for (Iterator<BaseModel> iterator = outputTypeCount.iterator(); iterator.hasNext(); ) {
            BaseModel obj = iterator.next();
            list.add(obj.getId());
            //list.add(obj.getPageNum());
        }

        return list;
    }

    public Object distinctSearch(Criteria criteria,String collectionName) {
        Aggregation aggregation = Aggregation.newAggregation(
                match(criteria),
                limit(2000));
        AggregationResults<HktGoodItemXcx> outputTypeCount = mongoTemplate.aggregate(aggregation, collectionName, HktGoodItemXcx.class);
        Map<String,Set<String>> treeMap = new TreeMap<>();
        Set<String> set = new TreeSet<>();
        for (Iterator<HktGoodItemXcx> iterator = outputTypeCount.iterator(); iterator.hasNext(); ) {
            HktGoodItemXcx obj = iterator.next();

            List<HktGoodsAttrItemXcx> attrs = obj.getAttrs();

            set.add(obj.getPackageSpecification());
            for(HktGoodsAttrItemXcx ha : attrs){
                if(treeMap.containsKey(ha.getAttrId())){
                    treeMap.get(ha.getAttrId()).add(ha.getAttrValue());
                }else {
                    Set<String> lt = new TreeSet<>();
                    lt.add(ha.getAttrValue());
                    treeMap.put(ha.getAttrId(),lt);
                }
            }
        }
        List<Object> reslut = new ArrayList<>();

        Map<String,Object> mm = new HashMap<>();
        mm.put("name","封装");
        mm.put("attrs",set);
        reslut.add(mm);
        for(Map.Entry<String, Set<String>> m : treeMap.entrySet()){
            Map<String,Object> map = new HashMap<>();
            if("阻值".equals(m.getKey())){
                List<Double> list1 = new ArrayList<>();
                List<Double> list2 = new ArrayList<>();
                List<Double> list3 = new ArrayList<>();
                for(String str : m.getValue()){
                    if(str.contains("K")){
                        list2.add(Double.parseDouble(str.replace("KΩ","")));
                    }else if(str.contains("M")) {
                        list3.add(Double.parseDouble(str.replace("MΩ","")));
                    }else {
                        list1.add(Double.parseDouble(str.replace("Ω","")));
                    }
                }
                List<String> c1 = list1.stream().sorted(Comparator.comparingDouble(str -> str)).map(x -> x.toString().endsWith(".0")?x.toString().replace(".0","")+"Ω" : x+"Ω").collect(Collectors.toList());
                List<String> c2 = list2.stream().sorted(Comparator.comparingDouble(str -> str)).map(x -> x.toString().endsWith(".0")?x.toString().replace(".0","")+"KΩ" : x+"KΩ").collect(Collectors.toList());
                List<String> c3 = list3.stream().sorted(Comparator.comparingDouble(str -> str)).map(x -> x.toString().endsWith(".0")?x.toString().replace(".0","")+"MΩ" : x+"MΩ").collect(Collectors.toList());

                Map<String,Object> m1 = new HashMap<>();
                Map<String,Object> m2 = new HashMap<>();
                Map<String,Object> m3 = new HashMap<>();
                m1.put("name","阻值R");
                m1.put("attrs",c1);
                m2.put("name","阻值K");
                m2.put("attrs",c2);
                m3.put("name","阻值M");
                m3.put("attrs",c3);
                reslut.add(m1);
                reslut.add(m2);
                reslut.add(m3);
            } else {
                map.put("name",m.getKey());
                map.put("attrs",m.getValue());
                reslut.add(map);
            }

        }
        return reslut;
    }


    public Set<String> distinctSearch1(Criteria criteria,String collectionName) {
        Aggregation aggregation = Aggregation.newAggregation(
                match(criteria));
//                limit(10000));
        AggregationResults<HktGoodItemXcx> outputTypeCount = mongoTemplate.aggregate(aggregation, collectionName, HktGoodItemXcx.class);
        Set<String> set = new TreeSet<>();
        for (Iterator<HktGoodItemXcx> iterator = outputTypeCount.iterator(); iterator.hasNext(); ) {
            HktGoodItemXcx obj = iterator.next();
            List<HktGoodsAttrItemXcx> attrs = obj.getAttrs();
            set.add(obj.getPackageSpecification());
            set.add(obj.getBrandName());
            for(HktGoodsAttrItemXcx ha : attrs){
                if(!set.contains(ha.getAttrValue())){
                    set.add(ha.getAttrValue());
                }
            }
        }
        return set;
    }


    public List<Map<String, Object>> distinct1(Criteria criteria, String field, String collectionName) {
        Aggregation aggregation = Aggregation.newAggregation(
                match(criteria),
                group(field).count().as("pageNum"));
        AggregationResults<BaseModel> outputTypeCount = mongoTemplate.aggregate(aggregation, collectionName, BaseModel.class);

        List<Map<String, Object>> list = new ArrayList<>();
        for (Iterator<BaseModel> iterator = outputTypeCount.iterator(); iterator.hasNext(); ) {
            BaseModel obj = iterator.next();
            Map<String, Object> map = new HashMap<>();
            map.put("name", obj.getId());
            map.put("count", obj.getPageNum());
            list.add(map);
        }

        return list;
    }

    /**
     * @param id     id
     * @param param  需要更新的实体对象
     * @param tClass 类名
     */
    public void mongoUpdate(String id, Object param, Class<T> tClass) {
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        Update update = new Update();
        Field[] fields = param.getClass().getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            String name = fields[i].getName();
            if ("_id".equals(name)) continue;
            Object value = ClassUtil.getFieldValueByName(name, param);
            if (StringUtils.isNull(value)) continue;
            update.set(name, value);
        }
        mongoTemplate.upsert(query, update, tClass);
    }

    /**
     * @param id     id
     * @param score  需要更新的实体对象
     * @param collectionName 类名
     */
    public void mongoUpdateById(String id, int score, String collectionName) {
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(id));
        Update update = new Update();
        mongoTemplate.upsert(query, update.inc("score",score), collectionName);
    }
}
