package cn.skcks.matrix.v2.services.casbin;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.casbin.jcasbin.main.Enforcer;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class CasbinServiceImpl implements CasbinService {
    private final Enforcer enforcer;

    @Override
    public boolean addRole(String role, String system, String url, String method) {
        return addRole(new Permission(Permission.Identify.ROLE, role, system, url, method));
    }

    @Override
    public boolean addRole(Permission permission) {
        if (!permission.getIdentify().equals(Permission.Identify.ROLE)) {
            return false;
        }

        enforcer.addPolicy(permission.getPolicyParam());
        return true;
    }

    @Override
    public void grantRole(String userId, String role, String system) {
        enforcer.addRoleForUserInDomain(Permission.Identify.getRoleName(Permission.Identify.USER, userId),
                Permission.Identify.getRoleName(Permission.Identify.ROLE, role),
                system);
    }

    @Override
    public void revokeRole(String userId, String role, String system) {
        enforcer.deleteRoleForUserInDomain(Permission.Identify.getRoleName(Permission.Identify.USER, userId),
                Permission.Identify.getRoleName(Permission.Identify.ROLE, role),
                system);
    }

    @Override
    public boolean enforce(String identify, String system, String url, String method) {
        return enforcer.enforce(identify, system, url, method);
    }

    @Override
    public List<String> getUserRoles(String userId, String system) {
        return enforcer.getRolesForUserInDomain(Permission.Identify.getRoleName(Permission.Identify.USER, userId), system);
    }

    @Override
    public List<String> getRoleUsers(String role, String system) {
        return enforcer.getUsersForRoleInDomain(Permission.Identify.getRoleName(Permission.Identify.ROLE, role), system)
                .parallelStream()
                .filter(item -> item.startsWith(Permission.Identify.USER.getPrefix()))
                .collect(Collectors.toList());
    }

    @Override
    public List<String> getRelationForRoleInSystem(String role, String system) {
        return enforcer.getImplicitUsersForRole(Permission.Identify.getRoleName(Permission.Identify.ROLE, role), system);
    }

    @Override
    public List<Permission> getUserPermission(String userId, String system) {
        List<List<String>> permissions = enforcer.getImplicitPermissionsForUserInDomain(Permission.Identify.getRoleName(Permission.Identify.USER, userId), system);
        return permissions.parallelStream()
                .map(permission -> new Permission(
                        Permission.Identify.ROLE,
                        permission.get(0),
                        permission.get(1),
                        permission.get(2),
                        permission.get(3)
                ))
                .toList();
    }

    @Override
    public boolean delRole(String role, String system) {
        if (getRelationForRoleInSystem(role, system).size() != 0) {
            return false;
        }

        enforcer.removeFilteredNamedPolicy("p", 0, Permission.Identify.getRoleName(Permission.Identify.ROLE, role), system);
        return true;
    }

    @Override
    public void reload() {
        enforcer.loadPolicy();
    }
}
