package com.njzscloud.common.http.resolver;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.njzscloud.common.http.annotation.QueryParam;
import com.njzscloud.common.http.constant.HttpMethod;
import com.njzscloud.common.http.processor.DefaultQueryParamProcessor;

import java.math.RoundingMode;
import java.util.*;

public class QueryParamResolver extends ParamResolver<QueryParam, String> {
    Map<String, List<String>> result = new TreeMap<>();

    public QueryParamResolver() {
        super(QueryParam.class);
    }

    @Override
    public String resolve(HttpMethod httpMethod, String urlTpl) {
        if (result.isEmpty()) return urlTpl;
        StringJoiner joiner = new StringJoiner("&", urlTpl + (urlTpl.contains("?") ? "&" : "?"), "");
        result.forEach((k, v) -> v.forEach(it -> joiner.add(k + "=" + it)));
        return joiner.toString();
    }

    @Override
    @SuppressWarnings("unchecked")
    protected boolean resolveParameter(QueryParam anno, String paramName, Class<?> paramClazz, Object paramValue) {
        String value = anno.value();
        if (isKv(paramClazz)) resolveKv(paramValue);
        else if (isArr(paramClazz)) resolveArr(StrUtil.isBlank(value) ? paramName : value, paramValue);
        else if (isStr(paramClazz) || isNum(paramClazz) || isDt(paramClazz)) resolveFormable(anno, paramName, paramClazz, paramValue);
        else return false;
        return true;
    }

    @Override
    @SuppressWarnings("unchecked")
    protected boolean resolveField(boolean hasParameterAnno, QueryParam anno, String paramName, Class<?> paramClazz, Object paramValue) {
        if (anno != null) {
            Class<? extends DefaultQueryParamProcessor> processorClazz = anno.processor();
            if (processorClazz != DefaultQueryParamProcessor.class) {
                ReflectUtil.newInstance(processorClazz).process(anno, paramName, paramClazz, paramValue, result);
            } else if (!hasParameterAnno && isKv(paramClazz)) {
                resolveKv(paramValue);
            }
        }
        if (anno != null) {
            String value = anno.value();
            if (StrUtil.isNotBlank(value)) paramName = value;
        }
        if (isArr(paramClazz)) resolveArr(paramName, paramValue);
        else resolveFormable(anno, paramName, paramClazz, paramValue);
        return true;
    }

    protected void resolveKv(Object paramValue) {
        ((Map<?, ?>) paramValue).forEach((k, v) -> {
            if (v == null) return;
            Class<?> clazz = v.getClass();
            String paramName = k.toString();
            if (isArr(clazz)) resolveArr(paramName, v);
            else resolveFormable(null, paramName, clazz, v);
        });
    }


    protected void resolveFormable(QueryParam anno, String paramName, Class<?> paramClazz, Object paramValue) {
        String key = paramName;
        String val;

        String format = null;
        RoundingMode roundingMode = null;
        if (anno != null) {
            format = anno.format();
            roundingMode = anno.roundingMode();
            String value = anno.value();
            if (StrUtil.isNotBlank(value)) key = value;
        }

        if (isNum(paramClazz)) {
            val = formatNum(format, roundingMode, paramValue);
        } else if (isDt(paramClazz)) {
            val = formatDt(format, paramValue);
        } else {
            val = paramValue.toString();
        }
        result.computeIfAbsent(key, it -> new ArrayList<>()).add(val);
    }

}
