package tech.easyflow.system.service.impl;

import org.springframework.stereotype.Service;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.system.enums.CategoryResourceType;
import tech.easyflow.system.enums.ResourceAction;
import tech.easyflow.system.enums.VisibilityScope;
import tech.easyflow.system.permission.resource.VisibilityResource;
import tech.easyflow.system.service.CategoryPermissionService;
import tech.easyflow.system.service.ResourceAccessService;
import tech.easyflow.system.service.SysDeptService;

import javax.annotation.Resource;
import java.math.BigInteger;

@Service
public class ResourceAccessServiceImpl implements ResourceAccessService {

    @Resource
    private CategoryPermissionService categoryPermissionService;

    @Resource
    private SysDeptService sysDeptService;

    @Override
    public boolean canAccess(CategoryResourceType resourceType, VisibilityResource resource, ResourceAction action) {
        return canAccess(SaTokenUtil.getLoginAccount(), resourceType, resource, action);
    }

    @Override
    public boolean canAccess(LoginAccount loginAccount, CategoryResourceType resourceType, VisibilityResource resource, ResourceAction action) {
        if (resource == null) {
            return false;
        }
        if (loginAccount == null || loginAccount.getId() == null) {
            return false;
        }
        BigInteger accountId = loginAccount.getId();
        if (categoryPermissionService.isSuperAdmin(loginAccount)) {
            return true;
        }
        if (accountId.equals(resource.getCreatedBy())) {
            return true;
        }
        if (ResourceAction.MANAGE == action) {
            return false;
        }
        if (!categoryPermissionService.canAccessCategory(loginAccount, resourceType.getCode(), resource.getCreatedBy(), resource.getCategoryId())) {
            return false;
        }
        VisibilityScope scope = VisibilityScope.fromOrDefault(resource.getVisibilityScope(), VisibilityScope.PRIVATE);
        if (VisibilityScope.PUBLIC == scope) {
            return true;
        }
        if (VisibilityScope.DEPT == scope) {
            return sysDeptService.canUserAccessDeptScopedResource(loginAccount.getDeptId(), resource.getDeptId());
        }
        return false;
    }

    @Override
    public void assertAccess(CategoryResourceType resourceType, VisibilityResource resource, ResourceAction action, String message) {
        if (!canAccess(resourceType, resource, action)) {
            throw new BusinessException(message == null ? "无权限访问该资源" : message);
        }
    }
}
