package com.brframework.commoncms.core.layout.layout;

import com.brframework.commonsecurity.core.SecurityContextHolder;
import com.brframework.commonweb.exception.HandleException;
import com.brframework.commonweb.json.JSONResult;
import com.google.common.collect.Lists;
import com.brframework.commoncms.annatotion.layout.ListLayout;
import com.brframework.commoncms.annatotion.option.CmsOption;
import com.brframework.commoncms.core.Option;
import com.brframework.commoncms.core.layout.AbstractPanelLayout;
import com.brframework.commoncms.core.layout.PanelLayoutColumn;
import com.brframework.commoncms.core.option.DefOption;
import com.brframework.commoncms.utils.ControllerUtil;
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
 * @author xu
 * @date 2018/9/26 13:46
 */
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Data
public class PanelListLayout extends AbstractPanelLayout {
    /**
     * 数据列表
     */
    public static final String TYPE = "LIST";

    private List<PanelLayoutColumn> columns;

    /**
     * 列操作
     */
    private List<Option> columnOptions;

    /**
     * 数据查询地址
     */
    private String queryUrl;
    /**
     * 数据查询参数
     */
    private List<PanelLayoutColumn> queryParam;
    /**
     * 是否可以导出excel
     */
    private boolean exportExcel = false;

    @Override
    public String getType() {
        return TYPE;
    }

    @Override
    public void create(Method method) throws Throwable {
        init(method);
        Class<?> returnType = method.getReturnType();

        if (!returnType.getName().equals(JSONResult.class.getName())) {
            throw new HandleException("返回值类型" + returnType.getName() + "非协议类型");
        }

        ResolvableType methodType = ResolvableType.forMethodReturnType(method);

        //获取List
        ResolvableType pageType = methodType.getGeneric(0);
        if (!pageType.getRawClass().getName().equals(List.class.getName())) {
            throw new HandleException("分页返回值类型必须是" + List.class.getName());
        }

        //获取Data
        ResolvableType dataType = pageType.getGeneric(0);
        if (AnnotationUtils.findAnnotation(dataType.getRawClass(), ApiModel.class) == null) {
            throw new HandleException("返回值类型必须是ApiModel注解标识的类");
        }

        //在Data中读取字段生成返回列
        columns = Lists.newArrayList();
        List<Field> returnTypeFields = ControllerUtil.handlerPropertyField(
                ControllerUtil.getAllField(dataType.getRawClass())
        );
        for (Field returnTypeField : returnTypeFields) {
            columns.add(ControllerUtil.createColumn(returnTypeField));
        }

        //通过解析方法参数生成接口调用需要的数据
        List<Class> apiTypes = ControllerUtil.getParamApiModelClass(method);
        queryParam = Lists.newArrayList();
        for (Class apiType : apiTypes) {
            List<Field> declaredFields = ControllerUtil.handlerPropertyField(
                    ControllerUtil.getAllField(apiType)
            );
            for (Field declaredField : declaredFields) {
                queryParam.add(ControllerUtil.createColumn(declaredField));
            }

        }

        //加载uri里的参数，对查询url进行填充
        Map<String, String> uriParameter = ControllerUtil.getUriParameter(method);
        queryUrl = ControllerUtil.getControllerUrl(method);
        for (String key : uriParameter.keySet()) {
            queryUrl = queryUrl.replace("{" + key + "}", uriParameter.get(key));
        }

        //创建列操作
        columnOptions = createColumnOptions(method);
        //是否需要到处excel
        exportExcel = getExportExcel(method);
    }

    /**
     * 创建列操作
     * @param method
     * @return
     */
    private List<Option> createColumnOptions(Method method){
        ListLayout pageLayout = AnnotatedElementUtils.findMergedAnnotation(method, ListLayout.class);
        List<Option> optionList = Lists.newArrayList();
        for (CmsOption option : pageLayout.columnOptions()) {
            if(ControllerUtil.hasMethodOptionRole(method, option)){
                Option defOption = new DefOption();
                defOption.create(method, option);
                optionList.add(defOption);
            }

        }

        return optionList;
    }

    /**
     * 是否需要导出excel
     * @param method
     * @return
     */
    private boolean getExportExcel(Method method){
        ListLayout pageLayout = AnnotatedElementUtils.findMergedAnnotation(method, ListLayout.class);
        return pageLayout.exportExcel();
    }

}
