package org.jeecg.common.aspect;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.Dict;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.vo.DictModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 企业级 DictAspect
 * 功能：
 * 1. 自动翻译 @Dict 字段
 * 2. 支持 DTO/List/Map/IPage 任意嵌套
 * 3. JSON 动态添加 dictText 字段
 * 4. 批量字典查询
 * 5. 字段缓存优化
 */
@Slf4j
@Aspect
@Component
public class DictAspect {

    @Autowired
    private CommonAPI commonApi;

    /** 字段缓存 */
    private static final Map<Class<?>, List<Field>> FIELD_CACHE = new ConcurrentHashMap<>();
    /** 字典翻译缓存 dictCode -> value -> text */
    private static final Map<String, Map<String,String>> DICT_CACHE = new ConcurrentHashMap<>();
    /** 缓存过期时间 */
    private static final long CACHE_EXPIRE = 10 * 60 * 1000;
    /** 时间记录 */
    private static final Map<String,Long> CACHE_TIME = new ConcurrentHashMap<>();


    @Pointcut("execution(public * org.jeecg.modules..*Controller.*(..))")
    public void dictPointCut(){}

    @Around("dictPointCut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        Object result = pjp.proceed();
        if(!(result instanceof Result)){
            return result;
        }
        Object data = ((Result) result).getResult();
        if(data == null){
            return result;
        }
        /* ---------- 转 JSON ---------- */
        Object json = convertToJson(data);
        log.debug("DictAspect start translate: {}", data.getClass().getSimpleName());

        /* ---------- 收集字典值 ---------- */
        Map<String, Set<String>> dictCollector = new HashMap<>();
        collectDictValues(data, dictCollector);
        if(dictCollector.isEmpty()){
            ((Result) result).setResult(json);
            return result;
        }
        /* ---------- 批量翻译 ---------- */
        Map<String, List<DictModel>> dictMap = translateDict(dictCollector);
        /* ---------- 填充 dictText ---------- */
        fillDictText(json, data, dictMap);

        ((Result) result).setResult(json);
        return result;
    }

    /**
     * 转 JSON
     */
    private Object convertToJson(Object data){
        Object json = JSONObject.toJSON(data);

        if(json instanceof JSONObject){
            JSONObject ordered = new JSONObject(true);
            ordered.putAll((JSONObject) json);
            return ordered;
        }

        return json;
    }

    /**
     * 收集字典值
     */
    private void collectDictValues(Object obj, Map<String, Set<String>> dictCollector){
        if(obj == null){
            return;
        }

        /* IPage */
        if(obj instanceof IPage){
            collectDictValues(((IPage<?>) obj).getRecords(), dictCollector);
            return;
        }
        /* Collection */
        if(obj instanceof Collection){
            for(Object item : (Collection<?>) obj){
                collectDictValues(item, dictCollector);
            }
            return;
        }
        /* Map */
        if(obj instanceof Map){
            for(Object value : ((Map<?,?>) obj).values()){
                collectDictValues(value, dictCollector);
            }
            return;
        }
        /* 简单类型 */
        if(isSimpleType(obj.getClass())){
            return;
        }
        /* Bean扫描 */
        for(Field field : getAllFields(obj.getClass())){
            field.setAccessible(true);
            try{
                Object value = field.get(obj);
                if(value == null){
                    continue;
                }

                Dict dict = field.getAnnotation(Dict.class);
                if(dict != null){
                    String dictCode = buildDictCode(dict);
                    Set<String> set = dictCollector.computeIfAbsent(dictCode,k->new HashSet<>());
                    String[] arr = value.toString().split(",");
                    set.addAll(Arrays.asList(arr));
                    log.debug("DictAspect collect: field={}, value={}",field.getName(),value);
                }

                collectDictValues(value, dictCollector);
            }catch (Exception ignored){}
        }
    }

    /**
     * 批量字典翻译
     */
    private Map<String,List<DictModel>> translateDict(Map<String,Set<String>> dictCollector){
        Map<String,List<DictModel>> dictMap = new HashMap<>();

        /* 普通字典 */
        Set<String> normalDictCodes = new HashSet<>();
        Set<String> normalKeys = new HashSet<>();
        /* 表字典 */
        Map<String,Set<String>> tableDictQuery = new HashMap<>();

        for(String dictCode : dictCollector.keySet()){
            Set<String> values = dictCollector.get(dictCode);
            if(values.isEmpty()){
                continue;
            }

            if(dictCode.contains(",")){
                tableDictQuery.put(dictCode,values);
            }else{
                normalDictCodes.add(dictCode);
                normalKeys.addAll(values);
            }
        }
        /* =========================
            1 普通字典 一次SQL查询
        ========================= */
        if(!normalDictCodes.isEmpty()){
            String dictCodes = String.join(",",normalDictCodes);
            String keys = String.join(",",normalKeys);
            Map<String,List<DictModel>> many = commonApi.translateManyDict(dictCodes,keys);

            if(many != null){
                for(String dictCode : many.keySet()){
                    List<DictModel> list = many.get(dictCode);
                    if(list == null){
                        continue;
                    }

                    Map<String,String> cache = DICT_CACHE.computeIfAbsent(dictCode,k->new ConcurrentHashMap<>());
                    for(DictModel m:list){
                        cache.put(m.getValue(),m.getText());
                    }
                }
            }
        }
        /* =========================
           2 表字典查询（带缓存）
        ========================= */
        for(String dictCode : tableDictQuery.keySet()){
            Set<String> values = tableDictQuery.get(dictCode);
            Map<String,String> cache = DICT_CACHE.computeIfAbsent(dictCode,k->new ConcurrentHashMap<>());
            Set<String> missValues = new HashSet<>();

            for(String v:values){
                if(!cache.containsKey(v)){
                    missValues.add(v);
                }
            }

            if(!missValues.isEmpty()){
                String[] arr = dictCode.split(",");
                List<DictModel> list = commonApi.translateDictFromTableByKeys(arr[0], arr[1], arr[2], String.join(",",missValues));

                if(list != null){
                    for(DictModel m:list){
                        cache.put(m.getValue(),m.getText());
                    }
                }
            }

            /* 组装结果 */
            List<DictModel> result = new ArrayList<>();
            for(String v:values){
                String text = cache.get(v);
                if(text != null){
                    DictModel m = new DictModel();
                    m.setValue(v);
                    m.setText(text);
                    result.add(m);
                }
            }
            dictMap.put(dictCode,result);
        }

        /* 普通字典结果组装 */
        for(String dictCode : normalDictCodes){
            Set<String> values = dictCollector.get(dictCode);
            Map<String,String> cache = DICT_CACHE.get(dictCode);
            if(cache == null){
                continue;
            }

            List<DictModel> result = new ArrayList<>();
            for(String v:values){
                String text = cache.get(v);
                if(text != null){
                    DictModel m = new DictModel();
                    m.setValue(v);
                    m.setText(text);
                    result.add(m);
                }
            }
            dictMap.put(dictCode,result);
        }
        return dictMap;
    }

    /**
     * 填充 dictText
     */
    private void fillDictText(Object json, Object bean, Map<String,List<DictModel>> dictMap){
        if(bean == null){
            return;
        }
        /* JSONArray */
        if(json instanceof JSONArray && bean instanceof Collection){
            Iterator<?> itBean = ((Collection<?>) bean).iterator();

            for(Object j : (JSONArray) json){
                Object b = itBean.next();
                fillDictText(j,b,dictMap);
            }
            return;
        }

        /* JSONObject */
        if(json instanceof JSONObject){
            JSONObject jsonObj = (JSONObject) json;

            if(bean instanceof Map){
                for(String key : jsonObj.keySet()){
                    fillDictText(jsonObj.get(key), ((Map<?,?>) bean).get(key), dictMap);
                }
                return;
            }

            if(isSimpleType(bean.getClass())){
                return;
            }

            for(Field field : getAllFields(bean.getClass())){
                field.setAccessible(true);
                try{
                    Object value = field.get(bean);
                    if(value == null){
                        continue;
                    }

                    Dict dict = field.getAnnotation(Dict.class);
                    if(dict != null){
                        String dictCode = buildDictCode(dict);
                        List<DictModel> models = dictMap.get(dictCode);

                        if(models != null){
                            String text = translateValue(models,value.toString());
                            jsonObj.put(field.getName() + CommonConstant.DICT_TEXT_SUFFIX, text);
                            log.debug("DictAspect fill: {} -> {}",field.getName()+CommonConstant.DICT_TEXT_SUFFIX,text);
                        }
                    }

                    fillDictText(jsonObj.get(field.getName()), value, dictMap);
                }catch (Exception ignored){
                    System.out.println();
                }
            }
        }
    }

    /**
     * 字典值翻译
     */
    private String translateValue(List<DictModel> models,String value){
        if(models == null || models.isEmpty()){
            return value;
        }

        Map<String,String> map = new HashMap<>();
        for(DictModel m:models){
            map.put(m.getValue(),m.getText());
        }

        List<String> result = new ArrayList<>();
        for(String v:value.split(",")){
            String text = map.get(v);
            if(text != null){
                result.add(text);
            }
        }

        return String.join(",",result);
    }

    /**
     * 获取字段（缓存）
     */
    private List<Field> getAllFields(Class<?> clazz){

        return FIELD_CACHE.computeIfAbsent(clazz,k->{
            List<Field> fields = new ArrayList<>();
            Class<?> c = k;

            while(c != null && c != Object.class){
                fields.addAll(Arrays.asList(c.getDeclaredFields()));
                c = c.getSuperclass();
            }
            return fields;
        });
    }

    /**
     * 构建 dictCode
     */
    private String buildDictCode(Dict dict){
        if(dict.dictTable()!=null && !"".equals(dict.dictTable())){
            return dict.dictTable() + "," + dict.dicText() + "," + dict.dicCode();
        }
        return dict.dicCode();
    }

    /**
     * 判断简单类型
     */
    private boolean isSimpleType(Class<?> clazz){
        return clazz.isPrimitive()
                || clazz == String.class
                || Number.class.isAssignableFrom(clazz)
                || clazz == Boolean.class
                || clazz == Character.class
                || clazz.getName().startsWith("java.time")
                || clazz.getName().equals("java.util.Date");
    }
}
