package cn.axzo.msg.center.api.custombutton;

import cn.axzo.msg.center.api.enums.TodoActorType;
import cn.axzo.msg.center.service.enums.BizFinalStateEnum;
import cn.axzo.msg.center.service.enums.CodeDefinition;
import cn.axzo.msg.center.service.enums.PendingMessageStateEnum;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;

import static java.util.stream.Collectors.toSet;

/**
 * 提前设定的按钮配置
 *
 * @author yanglin
 */
@Data
public class ProposedButtonConfig {

    /**
     * 适用的按钮的角色
     */
    private TodoActorType actorType;
    /**
     * 按钮可见的状态. 没有传则忽略状态, 都可见
     */
    private Set<String> visibleStates;

    /**
     * 创建对待办发起人总是可见的按钮, 忽略业务最终状态
     */
    public static ProposedButtonConfig alwaysVisibleForPromoter() {
        return visibleForPromoterAndBizStates(Collections.emptyList());
    }

    /**
     * 创建对待办发起人总是可见的按钮, 忽略待办状态
     */
    public static ProposedButtonConfig alwaysVisibleForExecutor() {
        return visibleForExecutorAndTodoStates(Collections.emptyList());
    }

    /**
     * 创建待办发起者按钮. 根据状态来控制可见性
     *
     * @param visibleBizFinalStates 按钮可见的状态. 为空则忽略状态, 都可见
     */
    public static ProposedButtonConfig visibleForPromoterAndBizStates(BizFinalStateEnum... visibleBizFinalStates) {
        BizFinalStateEnum[] states = visibleBizFinalStates;
        if (states == null)
            states = new BizFinalStateEnum[0];
        return visibleForPromoterAndBizStates(Arrays.asList(states));
    }

    /**
     * 创建待办执行者按钮. 根据状态来控制可见性
     *
     * @param visibleTodoStates 按钮可见的状态. 为空则忽略状态, 都可见
     */
    public static ProposedButtonConfig visibleForExecutorAndTodoStates(PendingMessageStateEnum... visibleTodoStates) {
        PendingMessageStateEnum[] states = visibleTodoStates;
        if (states == null)
            states = new PendingMessageStateEnum[0];
        return visibleForExecutorAndTodoStates(Arrays.asList(states));
    }

    /**
     * 创建待办发起者按钮. 根据状态来控制可见性
     *
     * @param visibleBizFinalStates 按钮可见的状态. 为空则忽略状态, 都可见
     */
    public static ProposedButtonConfig visibleForPromoterAndBizStates(List<BizFinalStateEnum> visibleBizFinalStates) {
        ProposedButtonConfig proposedButtonConfig = new ProposedButtonConfig();
        proposedButtonConfig.setActorType(TodoActorType.TODO_PROMOTER);
        if (visibleBizFinalStates != null) {
            Set<String> visibleStates = visibleBizFinalStates.stream()
                    .map(Enum::name)
                    .collect(toSet());
            proposedButtonConfig.setVisibleStates(visibleStates);
        }
        return proposedButtonConfig;
    }

    /**
     * 创建待办执行者按钮. 根据状态来控制可见性
     *
     * @param visibleTodoStates 按钮可见的状态. 为空则忽略状态, 都可见
     */
    public static ProposedButtonConfig visibleForExecutorAndTodoStates(List<PendingMessageStateEnum> visibleTodoStates) {
        ProposedButtonConfig proposedButtonConfig = new ProposedButtonConfig();
        proposedButtonConfig.setActorType(TodoActorType.TODO_EXECUTOR);
        if (visibleTodoStates != null) {
            Set<String> visibleStates = visibleTodoStates.stream()
                    .map(Enum::name)
                    .collect(toSet());
            proposedButtonConfig.setVisibleStates(visibleStates);
        }
        return proposedButtonConfig;
    }

    /**
     * 判断待办发起者按钮是否可见
     */
    public boolean isVisible(BizFinalStateEnum state) {
        // 没有指定状态, 一直可见
        if (CollectionUtils.isEmpty(visibleStates))
            return true;
        return visibleStates.stream()
                .map(code -> CodeDefinition.findByCode(BizFinalStateEnum.class, code))
                .filter(Optional::isPresent)
                .map(Optional::get)
                .anyMatch(s -> s == state);
    }

    /**
     * 判断待办执行者按钮是否可见
     */
    public boolean isVisible(PendingMessageStateEnum state) {
        // 没有指定状态, 一直可见
        if (CollectionUtils.isEmpty(visibleStates))
            return true;
        return visibleStates.stream()
                .map(code -> CodeDefinition.findByCode(PendingMessageStateEnum.class, code))
                .filter(Optional::isPresent)
                .map(Optional::get)
                .anyMatch(s -> s == state);
    }

}