package com.ningdatech.carapi.datascope.aop;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ningdatech.carapi.datascope.model.DataScopeDto;
import com.ningdatech.carapi.datascope.model.DataScopeEntity;
import com.ningdatech.carapi.datascope.provider.DataScopeContext;
import com.ningdatech.carapi.user.security.auth.model.UserInfoDetails;
import com.ningdatech.carapi.user.util.LoginUserUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Objects;
import java.util.Optional;

/**
 * @program:
 * @description: 数据权限切面
 * LambdaDataScopeAspect
 * @author: PoffyZhang
 * @created: 2022/11/11 09:12
 */
@Aspect
@Component
@Slf4j
@AllArgsConstructor
@Order(10)
public class LambdaDataScopeAspect {

    @Pointcut("@annotation(com.ningdatech.carapi.datascope.aop.LambdaDataScope)")
    public void lambdaDataScopeAspect() {

    }

    @Before("lambdaDataScopeAspect() && @annotation(lambdaDataScope)")
    public void before(JoinPoint joinPoint, LambdaDataScope lambdaDataScope) throws Throwable {
        Optional<DataScopeDto> currentUserDataScoper = getCurrentUserDataScoper();
        if (!currentUserDataScoper.isPresent()) {
            return;
        }
        DataScopeDto dataScopeDto = currentUserDataScoper.get();
        LambdaQueryWrapper<DataScopeEntity> wrapper =
                (LambdaQueryWrapper) joinPoint.getArgs()[lambdaDataScope.wrapperIndex()];

        if (Objects.isNull(wrapper)) {
            return;
        }

        switch (lambdaDataScope.type()) {
            case ALL:
                wrapper.in(CollUtil.isNotEmpty(dataScopeDto.getRegionIds()), DataScopeEntity::getRegionId, dataScopeDto.getRegionIds())
                        .in(CollUtil.isNotEmpty(dataScopeDto.getCompanyIds()), DataScopeEntity::getCompanyId, dataScopeDto.getCompanyIds());
                break;
            case ONLY_REGION:
                wrapper.in(CollUtil.isNotEmpty(dataScopeDto.getRegionIds()), DataScopeEntity::getRegionId, dataScopeDto.getRegionIds());
                break;
            case ONLY_COMPANY:
                wrapper.in(CollUtil.isNotEmpty(dataScopeDto.getCompanyIds()), DataScopeEntity::getCompanyId, dataScopeDto.getCompanyIds());
                break;
            case REGION_TABLE:
                wrapper.in(CollUtil.isNotEmpty(dataScopeDto.getRegionIds()), DataScopeEntity::getId, dataScopeDto.getRegionIds());
                break;
            case COMPANY_TABLE:
                wrapper.in(CollUtil.isNotEmpty(dataScopeDto.getCompanyIds()), DataScopeEntity::getId, dataScopeDto.getCompanyIds())
                        .in(CollUtil.isNotEmpty(dataScopeDto.getRegionIds()), DataScopeEntity::getRegionId, dataScopeDto.getRegionIds());
                break;
            case NONE:
                break;
            default:
                wrapper.in(CollUtil.isNotEmpty(dataScopeDto.getRegionIds()), DataScopeEntity::getRegionId, dataScopeDto.getRegionIds())
                        .in(CollUtil.isNotEmpty(dataScopeDto.getCompanyIds()), DataScopeEntity::getCompanyId, dataScopeDto.getCompanyIds());
        }

    }

    public Optional<DataScopeDto> getCurrentUserDataScoper() {
        UserInfoDetails loginUser = LoginUserUtil.loginUserDetail();
        if (Objects.isNull(loginUser) || Objects.isNull(loginUser.getDataScope())) {
            return Optional.empty();
        }
        return DataScopeContext.getDataScope(loginUser.getDataScope());
    }
}