package com.njcn.rdms.module.project.framework.security.aop;

import com.njcn.rdms.framework.common.util.spring.SpringExpressionUtils;
import com.njcn.rdms.module.project.framework.security.annotation.CheckObjectPermission;
import com.njcn.rdms.module.project.framework.security.service.ObjectPermissionService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.njcn.rdms.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;

/**
 * 对象级权限切面。
 */
@Aspect
@Component
@Slf4j
public class ObjectPermissionAspect {

    private final Map<String, ObjectPermissionService> objectPermissionServiceMap;

    public ObjectPermissionAspect(List<ObjectPermissionService> objectPermissionServices) {
        this.objectPermissionServiceMap = objectPermissionServices.stream()
                .collect(Collectors.toMap(ObjectPermissionService::getObjectType, Function.identity()));
    }

    @Around("@annotation(checkObjectPermission)")
    public Object aroundPointCut(ProceedingJoinPoint joinPoint,
                                 CheckObjectPermission checkObjectPermission) throws Throwable {
        ObjectPermissionService permissionService = objectPermissionServiceMap.get(checkObjectPermission.objectType());
        if (permissionService == null) {
            throw invalidParamException("暂不支持对象类型：{}", checkObjectPermission.objectType());
        }
        Long objectId = resolveObjectId(joinPoint, checkObjectPermission.objectId());
        // 分发优先级：accessible（可访问性门禁）> visibilityFallback（读路径成员/可见性兜底）> memberOnly / permission（权限码）
        if (checkObjectPermission.accessible()) {
            permissionService.checkAccessible(objectId);
        } else if (checkObjectPermission.visibilityFallback()) {
            permissionService.checkPermissionOrVisibility(objectId, checkObjectPermission.permission());
        } else {
            permissionService.checkPermission(objectId, checkObjectPermission.permission(),
                    checkObjectPermission.memberOnly());
        }
        return joinPoint.proceed();
    }

    private Long resolveObjectId(ProceedingJoinPoint joinPoint, String expression) {
        Object parsedValue = SpringExpressionUtils.parseExpression(joinPoint, expression);
        if (parsedValue instanceof Number number) {
            return number.longValue();
        }
        if (parsedValue instanceof String value && StringUtils.hasText(value)) {
            try {
                return Long.parseLong(value.trim());
            } catch (NumberFormatException ex) {
                log.warn("[resolveObjectId][expression({}) value({}) 不是合法数字]", expression, value);
            }
        }
        if (Objects.isNull(parsedValue)) {
            throw invalidParamException("对象编号不能为空");
        }
        throw invalidParamException("对象编号解析失败：{}", expression);
    }

}
