package com.gci.boot.common.dict.aspect;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.gci.boot.annotation.fileUrl.FileUrl;
import com.gci.boot.common.dict.annotation.Dict;
import com.gci.boot.common.util.ClassReflectionUtil;
import com.gci.boot.common.util.JsonUtil;
import com.gci.boot.common.util.SpringContextUtil;
import com.gci.boot.common.vo.Result;
import com.gci.boot.constant.CommonConstant;
import com.gci.boot.modules.system.service.ISysDictService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Value;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 字典解析切面
 */
@Aspect
@Slf4j
@RequiredArgsConstructor
public class DictAspect {
    private final ISysDictService dictService;
    private static final ThreadLocal<Map<String, DateFormat>> dateFormatHolder = new ThreadLocal();
    @Value("${minio.fileUrl}")
    private String fileUrl;
    @Value("${minio.minioUrl}")
    private String minioUrl;
    
    private static String delFlag = "delFlag";

    // 定义切点Pointcut
    @Pointcut("execution(public * com.gci.boot.modules..*.*Controller.*(..))")
    public void excudeService() {
    }

    @Around("excudeService()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        long time1 = System.currentTimeMillis();
        Object result = pjp.proceed();
        long time2 = System.currentTimeMillis();
        log.debug("获取JSON数据 耗时：" + (time2 - time1) + "ms");
        long start = System.currentTimeMillis();
        result = this.parseDictText(result);
        long end = System.currentTimeMillis();
        log.debug("解析注入JSON数据  耗时" + (end - start) + "ms");
        return result;
    }

    private Object parseDictText(Object result) {
        if (result instanceof Result) {
            Object rslt = ((Result) result).getResult();
            ((Result) result).setResult(parseDictText(rslt));
            return result;
        }

        try {
            if (result == null) {
                return null;
            }

            Object record;
            if (result instanceof IPage) {
                List items = new ArrayList();
                Iterator iterator = ((IPage) result).getRecords().iterator();

                while (iterator.hasNext()) {
                    record = iterator.next();
                    items.add(this.parseObject(record));
                }

                return ((IPage) result).setRecords(items);
            } else if (result instanceof List) {
                List items = new ArrayList();
                Iterator iterator = ((List) result).iterator();

                while (iterator.hasNext()) {
                    record = iterator.next();
                    items.add(this.parseObject(record));
                }

                return items;
            } else if (result instanceof Map) {
                Map items = new LinkedHashMap();
                ((Map) result).forEach((k, v) ->
                        items.put(k, this.parseObject(v))
                );
                return items;
            } else {
                return parseObject(result);
            }
        } catch (Exception e) {
            log.error("字典标识转换失败", e);
        }
        dateFormatHolder.remove();
        return result;
    }

    /**
     * 翻译对象
     *
     * @param rslt
     * @return
     */
    private Object parseObject(Object rslt) {
        if(rslt == null){
            return null;
        }else if (rslt instanceof List) {
            return parseDictText(rslt);
        } else if (rslt instanceof Map) {
            return parseDictText(rslt);
            //基本类型不处理
        }else if (rslt.getClass().isPrimitive() || rslt.getClass().getName().startsWith("java.")) {
            return rslt;
        }

        Map<String, Object> map = BeanUtil.beanToMap(rslt);
        List<Field> fields = ClassReflectionUtil.getAllFields(rslt.getClass());
        boolean hasDelFlag = false;
        for (Field field : fields) {
        	if(delFlag.equals(field.getName())) {
        		hasDelFlag = true;
        		break;
        	}
        }
        for (Field field : fields) {
            boolean accessible = field.isAccessible();
            field.setAccessible(true);
            if (field.isAnnotationPresent(Dict.class)) {
                Dict dictAno = field.getAnnotation(Dict.class);
                String code = dictAno.dicCode();
                String text = dictAno.dicText();
                String table = dictAno.dictTable();
                String key = String.valueOf(map.get(field.getName()));

                //翻译字典值对应的txt
                String textValue = translateDictValue(code, text, table, key,hasDelFlag);

                log.debug(" 字典Val : " + textValue);
                log.debug(" __翻译字典字段__ " + field.getName() + CommonConstant.DICT_TEXT_SUFFIX + "： " + textValue);
                map.put(field.getName() + CommonConstant.DICT_TEXT_SUFFIX, textValue);
            } else if (field.isAnnotationPresent(FileUrl.class)) {
                String inFileUrl;
                HttpServletRequest request = SpringContextUtil.getHttpServletRequest();
                String header = request.getHeader(CommonConstant.IS_INNER);
                if (Convert.toBool(header,false)) {
                    inFileUrl = minioUrl;
                } else {
                    inFileUrl = fileUrl;
                }
                //文件url补充前缀
                String value = Convert.toStr(map.get(field.getName()));
                if (StrUtil.isNotBlank(value)) {
                    List<String> split = StrUtil.split(value, StrUtil.COMMA);
                    for (int i = 0; i < split.size(); i++) {
                        String s = split.get(i);
                        split.set(i,URLUtil.completeUrl(inFileUrl,s));
                    }
                    map.put(field.getName(),StrUtil.join(StrUtil.COMMA,split));
                }
            } else if (field.getType().getName().equals("java.util.Date") && field.isAnnotationPresent(JsonFormat.class)) {
                //date类型默认转换string格式化日期
                Object d = map.get(field.getName());
                if (d instanceof Date) {
                    JsonFormat jsonFormat = field.getAnnotation(JsonFormat.class);
                    DateFormat dateFormat;
                    if (StringUtils.isNotBlank(jsonFormat.pattern())) {
                        dateFormat = getDateFormat(jsonFormat.pattern());
                    } else {
                        dateFormat = getDateFormat("yyyy-MM-dd HH:mm:ss");
                    }
                    map.put(field.getName(), dateFormat.format((Date) d));
                }
            }else {
                Object o = map.get(field.getName());
                map.put(field.getName(), parseObject(o));
            }
            field.setAccessible(accessible);
        }
        return map;
    }

    /**
     * 翻译字典文本
     *
     * @param code
     * @param text
     * @param table
     * @param key
     * @return 字典文本
     */
    private String translateDictValue(String code, String text, String table, String key,boolean hasDelFlag) {
        if (StringUtils.isBlank(key)) {
            return null;
        }
        List<String> keys = Arrays.asList(key.split(","));
        String textValue;
        if (!StringUtils.isEmpty(table)) {
            log.debug("--DictAspect------dicTable=" + table + " ,dicText= " + text + " ,dicCode=" + code);
            textValue = keys.stream().map(String::trim).filter(k -> k.length() > 0)
                    .map(k -> dictService.queryTableDictTextByKey(table, text, code, k,hasDelFlag))
                    .filter(StringUtils::isNotBlank)
                    .collect(Collectors.joining(","));
        } else {
            textValue = keys.stream().map(String::trim).filter(k -> k.length() > 0)
                    .map(k -> dictService.queryDictTextByKey(code, k))
                    .filter(StringUtils::isNotBlank)
                    .collect(Collectors.joining(","));
        }
        return StringUtils.isNotBlank(textValue) ? textValue : null;
    }



    /**
     * SimpleDateFormat不是线程安全的，每个线程都要使用一个新的实例
     *
     * @param pattern
     * @return
     */
    private DateFormat getDateFormat(String pattern) {
        Map<String, DateFormat> dateFormatMap = dateFormatHolder.get();
        if (dateFormatMap == null) {
            dateFormatMap = new HashMap<>();
            dateFormatHolder.set(dateFormatMap);
        }
        DateFormat dateFormat = dateFormatMap.get(pattern);
        if (dateFormat == null) {
            dateFormat = new SimpleDateFormat(pattern);
            dateFormatMap.put(pattern, dateFormat);
        }
        return dateFormat;
    }
}
