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

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.gci.boot.common.dict.annotation.Dict;
import com.gci.boot.common.util.SpringContextUtil;
import com.gci.boot.constant.CacheConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
public class DictConverter implements Converter<Object> {

    private static DictParser dictParser;
    private static CacheManager cacheManager;

    public DictConverter() {
        dictParser = SpringContextUtil.getBean(DictParser.class);
        cacheManager = SpringContextUtil.getBean(CacheManager.class);
    }

    @Override
    public Class<?> supportJavaTypeKey() {
        return Converter.super.supportJavaTypeKey();
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    @Override
    public Object convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        try {
            if (StringUtils.isBlank(cellData.getStringValue())) {
                return null;
            }
            Field field = contentProperty.getField();
            if (field.isAnnotationPresent(Dict.class)) {
                Dict dictAnno = field.getAnnotation(Dict.class);
                String val;
                List<String> keys = Arrays.asList(cellData.getStringValue().split(","));
                if (StringUtils.isNotBlank(dictAnno.dictTable())) {
                    val = keys.stream().map(String::trim).filter(k->k.length()>0)
                            .map(k -> dictParser.queryTableDictValueByText(dictAnno.dictTable(), dictAnno.dicText(), dictAnno.dicCode(), k))
                            .collect(Collectors.joining(","));
                } else {
                    val = keys.stream().map(String::trim).filter(k->k.length()>0)
                            .map(k -> dictParser.queryDictValueByText(dictAnno.dicCode(), k))
                            .collect(Collectors.joining(","));
                }
                if (Integer.class.getName().equals(field.getType().getName())) {
                    return Integer.parseInt(val);
                }
                if("null".equals(val)) {
                	val = "";
                }
                return val;
            }
        } catch (Exception e) {
            log.error("", e);
        }
        return null;
    }

    @Override
    public WriteCellData<?> convertToExcelData(Object value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        try {
            if (value == null || value.toString().trim().length() == 0) {
                return new WriteCellData<>("");
            }
            Field field = contentProperty.getField();
            if (field.isAnnotationPresent(Dict.class)) {
                Dict dictAnno = field.getAnnotation(Dict.class);
                List<String> keys = Arrays.asList(value.toString().split(","));
                String val;
                if (StringUtils.isNotBlank(dictAnno.dictTable())) {
                    val = keys.stream().map(String::trim).filter(k->k.length()>0)
                            .map(k -> getTableDictTextByKey(dictAnno, k))
                            .collect(Collectors.joining(","));
                } else {
                    val = keys.stream().map(String::trim).filter(k->k.length()>0)
                            .map(k -> getDictTextByKey(dictAnno, k))
                            .collect(Collectors.joining(","));
                }
                if("null".equals(val)) {
                	val = "";
                }
                return new WriteCellData<>(val);
            }
        } catch (Exception e) {
            log.error("", e);
        }
        return new WriteCellData<>(value.toString());
    }

    private String getDictTextByKey(Dict dictAnno, String k) {
        Cache cache = cacheManager.getCache(CacheConstant.SYS_DICT_CACHE);
        String cacheKey = dictAnno.dicCode() + ":" + k;
        if (ObjectUtil.isNotNull(cache)) {
            Cache.ValueWrapper valueWrapper = cache.get(cacheKey);
            if (ObjectUtil.isNotNull(valueWrapper)) {
                return Convert.toStr(valueWrapper.get());
            }
        }
        String sqlValue = dictParser.queryDictTextByKey(dictAnno.dicCode(), k);
        if (ObjectUtil.isNotNull(cache)) {
            if (StrUtil.isNotBlank(sqlValue)) {
                cache.put(cacheKey,sqlValue);
            }
        }
        return sqlValue;
    }

    private String getTableDictTextByKey(Dict dictAnno, String k) {
        Cache cache = cacheManager.getCache(CacheConstant.SYS_DICT_TABLE_CACHE);
        String cacheKey = dictAnno.dictTable() + ":" + dictAnno.dicCode() + ":" + k + ":" + false;
        if (ObjectUtil.isNotNull(cache)) {
            Cache.ValueWrapper valueWrapper = cache.get(cacheKey);
            if (ObjectUtil.isNotNull(valueWrapper)) {
                return Convert.toStr(valueWrapper.get());
            }
        }
        String sqlValue = dictParser.queryTableDictTextByKey(dictAnno.dictTable(), dictAnno.dicText(), dictAnno.dicCode(), k);
        if (ObjectUtil.isNotNull(cache)) {
            if (StrUtil.isNotBlank(sqlValue)) {
                cache.put(cacheKey,sqlValue);
            }
        }
        return sqlValue;
    }

}
