package com.topsunit.query.binding;

import com.huigou.data.domain.query.QueryAbstractRequest;
import com.topsunit.query.annotations.Param;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Collection;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author yonghuan
 */
public abstract class AbstractQueryRequestFactory implements QueryRequestFactory {

    private final static Logger LOG = LoggerFactory.getLogger(AbstractQueryRequestFactory.class);
    @Override
    public QueryAbstractRequest getQueryRequest(Method method, Object[] args) {
        long startTime = System.currentTimeMillis();
        QueryAbstractRequest queryRequest = newInstance(method, args);
        LOG.info("为查询方法 {}.{} 生成QueryRequest,共花费{}毫秒", method.getDeclaringClass().getName(), method.getName(), System.currentTimeMillis() - startTime);
        PropertyDescriptor[] propertyDescriptors;
        try {
            propertyDescriptors = Introspector.getBeanInfo(queryRequest.getClass()).getPropertyDescriptors();
        } catch (IntrospectionException ie) {
            throw new IllegalArgumentException(ie);
        }
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            Param paramAnnotation = parameter.getAnnotation(Param.class);
            if (paramAnnotation != null) {
                String paramName = paramAnnotation.value();
                PropertyDescriptor propertyDescriptor = Stream.of(propertyDescriptors)
                        .filter(pd -> pd.getName().equals(paramName))
                        .findAny()
                        .orElseThrow(() -> new IllegalArgumentException(String.format("无法匹配查询参数 %s", paramName)));
                Object paramVal = args[i];
                if (paramVal instanceof Collection) {
                    Collection<?> items = (Collection<?>) paramVal;
                    paramVal = items.stream().map(String::valueOf).collect(Collectors.joining(","));
                }
                try {
                    propertyDescriptor.getWriteMethod().invoke(queryRequest, paramVal);
                } catch (IllegalAccessException | InvocationTargetException e) {
                    throw new IllegalArgumentException(String.format("绑定参数 paramName=%s，paramValue=%s 时候出错", paramName, paramVal), e);
                }
            }
        }
        return queryRequest;
    }

    protected abstract QueryAbstractRequest newInstance(Method method, Object[] args);
}
