package tech.easyflow.approval.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.stereotype.Component;
import tech.easyflow.approval.annotation.ApprovalAction;
import tech.easyflow.approval.entity.vo.ApprovalSubmitRequest;
import tech.easyflow.approval.entity.vo.ApprovalActionResult;
import tech.easyflow.approval.service.ApprovalSubjectHandler;
import tech.easyflow.approval.service.ApprovalActionFacade;
import tech.easyflow.common.satoken.util.SaTokenUtil;

import java.lang.reflect.Method;
import java.math.BigInteger;
import java.util.List;

/**
 * 提审动作切面。
 */
@Aspect
@Component
public class ApprovalActionAspect {

    private final ApprovalActionFacade approvalActionFacade;
    private final List<ApprovalSubjectHandler> handlers;
    private final ExpressionParser expressionParser = new SpelExpressionParser();
    private final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

    public ApprovalActionAspect(ApprovalActionFacade approvalActionFacade,
                                List<ApprovalSubjectHandler> handlers) {
        this.approvalActionFacade = approvalActionFacade;
        this.handlers = handlers;
    }

    /**
     * 拦截提审方法，先执行资源校验，再统一发起审批。
     *
     * @param joinPoint 切点
     * @param approvalAction 注解
     * @return 动作执行结果
     * @throws Throwable 执行异常
     */
    @Around("@annotation(approvalAction)")
    public Object doAround(ProceedingJoinPoint joinPoint, ApprovalAction approvalAction) throws Throwable {
        Object identifier = resolveIdentifier(joinPoint, approvalAction.idExpr());
        BigInteger resourceId = identifier == null ? null : new BigInteger(String.valueOf(identifier));
        joinPoint.proceed();
        ApprovalSubjectHandler handler = getHandler(approvalAction.resourceType());
        ApprovalSubmitRequest request = handler.buildSubmitRequest(
                resourceId,
                approvalAction.actionType(),
                SaTokenUtil.getLoginAccount().getId()
        );
        ApprovalActionResult result = approvalActionFacade.submit(request);
        return result;
    }

    private Object resolveIdentifier(ProceedingJoinPoint joinPoint, String idExpr) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        MethodBasedEvaluationContext context = new MethodBasedEvaluationContext(
                joinPoint.getTarget(),
                method,
                joinPoint.getArgs(),
                parameterNameDiscoverer
        );
        return expressionParser.parseExpression(idExpr).getValue(context);
    }

    private ApprovalSubjectHandler getHandler(String resourceType) {
        return handlers.stream()
                .filter(item -> item.resourceType().equals(resourceType))
                .findFirst()
                .orElseThrow(() -> new IllegalStateException("未找到审批处理器: " + resourceType));
    }
}
