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

import com.brframework.commoncms.utils.ControllerUtil;
import com.brframework.commonweb.core.SpringContext;
import com.brframework.commonweb.exception.HandleException;
import com.google.common.collect.Lists;
import com.brframework.commoncms.annatotion.column.TextColumn;
import com.brframework.commoncms.core.layout.AbstractPanelLayoutColumn;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.constraints.Length;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;

import javax.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * 文本输入
 *
 * @author xu
 * @date 2018/9/26 14:01
 * @see TextColumn
 */
@Data
public class LayoutTextColumn extends AbstractPanelLayoutColumn {

    private static final String TYPE_DEF = "TEXT";
    private String key;
    private String title;

    /**
     * 文本最短的长度
     */
    private Integer minInput;

    /**
     * 文本最大的长度
     */
    private Integer maxInput;

    /**
     * 是否为只读:true为只读,默认为false
     */
    private Boolean onlyRead;

    /**
     * 提示信息,在文本框的内容为空的时候的提示信息
     * 当仅仅当使用了{@link TextColumn} 注解的字段才会返回hintText字段给前端
     */
    private String hintText;

    /**
     * 链接 uri
     * {PROTOCOL}://{path}
     */
    private String linkUri;

    @Override
    public String getKey() {
        return key;
    }

    @Override
    public String getTitle() {
        return title;
    }


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

    /**
     * 1：最大值必须大于等于最小值
     * 2：如果该列即没有使用{@link NotNull}注解,也没有使用{@link Length}注解,则最大值和最小值均为0.
     * 3：如果该列仅使用了{@link NotNull}注解,那么最小值为1,最大值为{@link Integer#MAX_VALUE}
     * 4：如果该列仅使用了{@link Length}注解,但是没有使用{@link Length#min()}和{@link Length#max()},那么使用的是他们的默认值
     * 5：如果该列仅使用了{@link Length}注解,但使用{@link Length#min()}和{@link Length#max()},那么就为设置的值
     * 6：如果{@link NotNull}注解和{@link Length}注解均使用了,那最小值就看{@link Length#min()}和1谁大,谁大最小值就是谁;最大值
     * 就看{@link Length#max()}和{@link Integer#MAX_VALUE}谁小,谁小最大值就是谁
     *
     * @param columnField 对应列
     * @return 最小值
     */
    private Integer getMinInput(Field columnField) {
        NotNull notNull = AnnotationUtils.findAnnotation(columnField, NotNull.class);
        Length length = AnnotationUtils.findAnnotation(columnField, Length.class);
        int minLen = notNull != null ? 1 : 0;
        return length != null && length.min() > 0 ? length.min() : minLen;
    }

    /**
     * {@link #getMinInput}
     *
     * @param columnField 对应列
     * @return 最大值
     */
    private Integer getMaxInput(Field columnField) {
        NotNull notNull = AnnotationUtils.findAnnotation(columnField, NotNull.class);
        Length length = AnnotationUtils.findAnnotation(columnField, Length.class);
        int maxLen = notNull != null ? Integer.MAX_VALUE : 0;
        return length != null ? length.max() : maxLen;
    }

    /**
     * 获取该文本输入是否为只读
     *
     * @param columnField 对应列
     * @return 是否为只读
     */
    private boolean isOnlyRead(Field columnField) {
        TextColumn textColumn = AnnotationUtils.findAnnotation(columnField, TextColumn.class);
        return textColumn != null && textColumn.onlyRead();
    }

    /**
     * 获取该文本输入的提示信息
     *
     * @param columnField 对应列
     * @return 在文本框的内容为空的时候的提示信息
     */
    private String getHintText(Field columnField) {
        TextColumn textColumn = AnnotationUtils.findAnnotation(columnField, TextColumn.class);
        return textColumn != null ? textColumn.hintText() : null;
    }

    /**
     * 解析link uri
     * @param columnField
     */
    public void parseLinkUri(Field columnField) {
        TextColumn textColumn = AnnotationUtils.findAnnotation(columnField, TextColumn.class);
        if(textColumn == null) return;

        if(StringUtils.isNotEmpty(textColumn.uri())){
            linkUri = textColumn.uri();
            return;
        }

        String uriMappingMethod = textColumn.uriMappingMethod();
        String springBeanName = uriMappingMethod.split("\\.")[0];
        String beanMethodName = uriMappingMethod.split("\\.")[1];

        Object bean = SpringContext.getBean(springBeanName);
        Method method = Arrays.stream(bean.getClass().getDeclaredMethods())
                .filter(p -> p.getName().equals(beanMethodName)).findFirst().get();

        linkUri = ControllerUtil.parseMethodUriProtocol(method, null).toString();

    }

    @Override
    public void create(Field columnField) throws Throwable {
        init(columnField);

        //设置最大最小值
        setMinInput(getMinInput(columnField));
        setMaxInput(getMaxInput(columnField));

        //设置的最大值不能比最小值小
        if (maxInput < minInput) {
            throw new HandleException(columnField.getDeclaringClass().getName()
                    + "." + columnField.getName() + "字段的最大值不能比最小值小");
        }

        //设置是否只读
        setOnlyRead(isOnlyRead(columnField));
        //设置提示信息
        setHintText(getHintText(columnField));

        parseLinkUri(columnField);
    }


    @Override
    public List<Class<?>> supportType() {
        return Lists.newArrayList(
                String.class,
                CharSequence.class
        );
    }
}
