package com.apobates.forum.strategy.exposure;

import com.apobates.forum.event.elderly.ForumActionEnum;
import com.apobates.forum.member.entity.Member;
import com.apobates.forum.member.entity.MemberRoleEnum;
import com.apobates.forum.strategy.exception.VerificaFailException;
import com.apobates.forum.utils.lang.TriPredicate;
import java.util.Optional;
import java.util.Set;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.ImmutableTriple;

/**
 * 检测器执行链,并封装执行结果
 * 
 * @param <T>
 * @author xiaofanku
 * @since 20200805
 */
public final class DetectionStrategyChain<T> {
    private final boolean result;
    private final VerificaFailException exception;
    
    private DetectionStrategyChain(boolean result, VerificaFailException exception) {
        this.result = result;
        this.exception = exception;
    }
    
    public static <T> DetectionStrategyChain<T> begin() {
        return new DetectionStrategyChain<>(true, null);
    }
    /**
     * 
     * @param entityStrategy 实体检查策略
     * @param argument 检查策略参数
     * @return 
     */
    public DetectionStrategyChain<T> entity(BiPredicate<T, ForumActionEnum> entityStrategy, ImmutablePair<T, ForumActionEnum> argument){
        if(!isContinue()){
            return this;
        }
        //
        try{
            if(entityStrategy.test(argument.getLeft(), argument.getRight())){
                return new DetectionStrategyChain<>(true, null);
            }
        }catch(VerificaFailException e){
            return new DetectionStrategyChain<>(false, e);
        }
        return new DetectionStrategyChain<>(false, new VerificaFailException("实体策略检测失败"));
    }
    /**
     * 
     * @param memberStrategy 操作者/会员检查策略
     * @param operator 操作者/会员
     * @return 
     */
    public DetectionStrategyChain<T> member(Predicate<Member> memberStrategy, Member operator){
        if(!isContinue()){
            return this;
        }
        //
        try{
            if(memberStrategy.test(operator)){
                return new DetectionStrategyChain<>(true, null);
            }
        }catch(VerificaFailException e){
            return new DetectionStrategyChain<>(false, e);
        }
        return new DetectionStrategyChain<>(false, new VerificaFailException("会员策略检测失败"));
    }
    /**
     * 
     * @param actionStrategy 操作权限检查策略
     * @param argument 检查策略参数
     * @return 
     */
    public DetectionStrategyChain<T> action(TriPredicate<Member, ForumActionEnum, Set<MemberRoleEnum>> actionStrategy, ImmutableTriple<Member, ForumActionEnum, Set<MemberRoleEnum>> argument){
        if(!isContinue()){
            return this;
        }
        //
        try{
            if(actionStrategy.test(argument.getLeft(), argument.getMiddle(), argument.getRight())){
                return new DetectionStrategyChain<>(true, null);
            }
        }catch(VerificaFailException e){
            return new DetectionStrategyChain<>(false, e);
        }
        return new DetectionStrategyChain<>(false, new VerificaFailException("权限策略检测失败"));
    }
    
    public boolean isContinue(){
        return result;
    }
    
    public Optional<VerificaFailException> getBreakException(){
        return Optional.ofNullable(exception);
    }
}