package cn.axzo.msg.center.message.service.todo.card.workflow;

import cn.axzo.msg.center.domain.entity.Todo;
import cn.axzo.msg.center.message.service.card.interceptor.CardButtonInterceptor;
import cn.axzo.msg.center.service.ButtonV3;
import cn.axzo.msg.center.service.enums.BizFinalStateEnum;
import cn.axzo.msg.center.service.enums.PendingMessageStateEnum;
import cn.axzo.msg.center.service.enums.RouterButtonSourceEnum;
import cn.axzo.msg.center.utils.desision.DecisionValue;
import cn.axzo.workflow.common.enums.BpmnProcessTaskResultEnum;
import cn.axzo.workflow.common.enums.ButtonVisibleScopeEnum;
import cn.axzo.workflow.common.model.request.bpmn.BpmnButtonMetaInfo;
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskButtonVo;
import cn.axzo.workflow.common.model.response.bpmn.task.BpmnTaskButtonVo.BpmnButtonMetaInfoWithVisibleScope;
import com.google.common.collect.Sets;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

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
 */
@Slf4j
@RequiredArgsConstructor
class WorkflowTodoCardButtonInterceptor implements CardButtonInterceptor {

    private final static Set<String> SYSTEM_BUTTONS_SENDER_SHOW = Sets.newHashSet(
            BizFinalStateEnum.RETRACT.getButtonCode());
    private final static Set<String> SYSTEM_BUTTONS_EXECUTOR_SHOW = Sets.newHashSet(
            BizFinalStateEnum.PASSED.getButtonCode(),
            BizFinalStateEnum.REJECTED.getButtonCode());

    private final Todo todo;
    private final BpmnTaskButtonVo taskInfo;

    @Override
    public DecisionValue<Boolean> isPerformActionAvailable(ButtonV3 button) {
        BizFinalStateEnum btnBizState = findButtonClickState(button).orElse(null);
        return DecisionValue.decide(btnBizState != null && btnBizState.isButtonPerformActionAvailable());
    }

    @Override
    public DecisionValue<Boolean> isActionPerformed(ButtonV3 button) {
        return DecisionValue.decide(isSystemButtonActionPerformed(button));
    }

    private boolean isSystemButtonActionPerformed(ButtonV3 button) {
        return isExecutorActionPerformed(button) || isSenderActionPerformed(button);
    }

    private boolean isExecutorActionPerformed(ButtonV3 button) {
        BizFinalStateEnum btnBizState = findButtonClickState(button).orElse(null);
        if (btnBizState == null)
            return false;
        if (btnBizState == BizFinalStateEnum.PASSED
                && taskInfo.getExecutorTaskResult() == BpmnProcessTaskResultEnum.APPROVED)
            return true;
        return btnBizState == BizFinalStateEnum.REJECTED
                && taskInfo.getExecutorTaskResult() == BpmnProcessTaskResultEnum.REJECTED;
    }

    private boolean isSenderActionPerformed(ButtonV3 button) {
        BizFinalStateEnum btnBizState = findButtonClickState(button).orElse(null);
        if (btnBizState == null)
            return false;
        return btnBizState == BizFinalStateEnum.RETRACT
                && taskInfo.getInitiatorTaskResult() == BpmnProcessTaskResultEnum.CANCELED;
    }

    @Override
    public DecisionValue<String> getActionPerformedName(ButtonV3 button) {
        BizFinalStateEnum btnBizState = findButtonClickState(button).orElse(null);
        return btnBizState == null
                ? DecisionValue.notSure()
                : DecisionValue.decide(btnBizState.getActionPerformedName());
    }

    @Override
    public DecisionValue<Boolean> isVisibleOnCard(ButtonV3 button) {
        // 进行中隐藏所有按钮
        if (todo.getState() == PendingMessageStateEnum.PROCESSING)
            return DecisionValue.decide(false);
        // 显示失效按钮
        if (isSystemButtonActionPerformed(button))
            return DecisionValue.notSure();
        if (getWorkflowHideButtonKeys().contains(button.getCode()))
            return DecisionValue.decide(false);
        if (button.getSource() == RouterButtonSourceEnum.CUSTOM)
            return DecisionValue.notSure();
        BpmnButtonMetaInfoWithVisibleScope workflowButton = findWorkflowButton(button).orElse(null);
        // 如果找不到流程按钮, 说明不需要显示按钮，否则是否显示由待办模版控制
        return workflowButton == null ? DecisionValue.decide(false) : DecisionValue.notSure();
    }

    @Override
    public DecisionValue<Boolean> isSenderShow(ButtonV3 button) {
        if (button.getSource() == RouterButtonSourceEnum.CUSTOM)
            return DecisionValue.decide(false);
        return DecisionValue.decide(SYSTEM_BUTTONS_SENDER_SHOW.contains(button.getCode()));
    }

    @Override
    public DecisionValue<Boolean> isExecutorShow(ButtonV3 button) {
        if (button.getSource() == RouterButtonSourceEnum.CUSTOM)
            return DecisionValue.notSure();
        if (SYSTEM_BUTTONS_EXECUTOR_SHOW.contains(button.getCode()))
            return DecisionValue.decide(true);
        BpmnButtonMetaInfoWithVisibleScope workflowButton = findWorkflowButton(button).orElse(null);
        if (workflowButton == null)
            return DecisionValue.notSure();
        List<ButtonVisibleScopeEnum> scopes = workflowButton.getVisibleScopes();
        return DecisionValue.decide(scopes != null
                && scopes.contains(ButtonVisibleScopeEnum.EXECUTOR)
                && !scopes.contains(ButtonVisibleScopeEnum.INITIATOR));
    }

    private Optional<BizFinalStateEnum> findButtonClickState(ButtonV3 button) {
        if (button.getSource() == RouterButtonSourceEnum.CUSTOM)
            return Optional.empty();
        return BizFinalStateEnum.findButtonClickedState(button.getCode());
    }

    private Optional<BpmnButtonMetaInfoWithVisibleScope> findWorkflowButton(ButtonV3 button) {
        List<BpmnButtonMetaInfoWithVisibleScope> workflowButtons = this.taskInfo.getButtons();
        if (workflowButtons == null)
            workflowButtons = Collections.emptyList();
        return workflowButtons.stream()
                .filter(workflowButton -> workflowButton.getBtnKey().equals(button.getCode()))
                .findFirst();
    }

    private Set<String> getWorkflowHideButtonKeys() {
        List<BpmnButtonMetaInfo> workflowHiddenButtons = taskInfo.getCustomHiddenButtons();
        if (workflowHiddenButtons == null)
            workflowHiddenButtons = Collections.emptyList();
        return workflowHiddenButtons.stream()
                .map(BpmnButtonMetaInfo::getBtnKey)
                .collect(toSet());
    }

}