package com.bonus.material.approval.aspect;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.bonus.common.core.exception.ServiceException;
import com.bonus.material.approval.annotation.ApprovalRequired;
import com.bonus.material.approval.domain.ApprovalInstance;
import com.bonus.material.approval.service.IApprovalEngineService;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;

/**
 * 审批切面
 * 拦截带有@ApprovalRequired注解的方法，自动创建审批实例
 * 
 * @author syruan
 */
@Aspect
@Component
public class ApprovalAspect {

    private static final Logger log = LoggerFactory.getLogger(ApprovalAspect.class);

    @Resource
    private IApprovalEngineService approvalEngineService;

    /**
     * SpEL表达式解析器
     */
    private final ExpressionParser parser = new SpelExpressionParser();

    /**
     * 参数名发现器
     */
    private final DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();

    @Around("@annotation(com.bonus.material.approval.annotation.ApprovalRequired)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 1. 获取注解信息
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        ApprovalRequired annotation = method.getAnnotation(ApprovalRequired.class);

        // 2. 执行业务方法
        Object result = joinPoint.proceed();

        // 3. 判断是否需要审批
        if (!approvalEngineService.needApproval(annotation.businessType())) {
            log.debug("业务类型[{}]未配置审批流程，跳过审批", annotation.businessType());
            return result;
        }

        // 4. 判断条件表达式
        if (StrUtil.isNotBlank(annotation.condition())) {
            EvaluationContext context = createEvaluationContext(joinPoint, result);
            Expression expression = parser.parseExpression(annotation.condition());
            Boolean needApproval = expression.getValue(context, Boolean.class);
            if (needApproval == null || !needApproval) {
                log.debug("不满足审批条件[{}]，跳过审批", annotation.condition());
                return result;
            }
        }

        // 5. 解析业务ID
        Object businessIdObj = parseExpression(annotation.businessIdExpr(), joinPoint, result, Object.class);
        if (businessIdObj == null) {
            throw new ServiceException("无法解析业务ID，表达式：" + annotation.businessIdExpr());
        }
        String businessId = String.valueOf(businessIdObj);

        // 6. 解析业务数据
        Object businessDataObj = parseExpression(annotation.businessDataExpr(), joinPoint, result, Object.class);
        String businessData = JSON.toJSONString(businessDataObj);

        // 7. 创建审批实例
        try {
            ApprovalInstance instance = approvalEngineService.createApprovalInstance(
                    annotation.businessType(), businessId, businessData);
            
            log.info("自动创建审批实例成功，业务类型：{}，业务ID：{}，实例编号：{}",
                    annotation.businessType(), businessId, instance.getInstanceCode());
        } catch (Exception e) {
            log.error("创建审批实例失败，业务类型：{}，业务ID：{}",
                    annotation.businessType(), businessId, e);
            throw new ServiceException("创建审批实例失败：" + e.getMessage());
        }

        return result;
    }

    /**
     * 创建SpEL上下文
     */
    private EvaluationContext createEvaluationContext(ProceedingJoinPoint joinPoint, Object result) {
        StandardEvaluationContext context = new StandardEvaluationContext();
        
        // 设置方法参数
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String[] paramNames = discoverer.getParameterNames(signature.getMethod());
        Object[] args = joinPoint.getArgs();
        
        if (paramNames != null) {
            for (int i = 0; i < paramNames.length; i++) {
                context.setVariable(paramNames[i], args[i]);
            }
        }
        
        // 设置返回值
        context.setVariable("result", result);
        
        return context;
    }

    /**
     * 解析SpEL表达式
     */
    private <T> T parseExpression(String expressionString, ProceedingJoinPoint joinPoint, 
                                   Object result, Class<T> clazz) {
        try {
            EvaluationContext context = createEvaluationContext(joinPoint, result);
            Expression expression = parser.parseExpression(expressionString);
            return expression.getValue(context, clazz);
        } catch (Exception e) {
            log.error("解析表达式失败：{}", expressionString, e);
            return null;
        }
    }
}

