package tech.easyflow.ai.permission;

import com.mybatisflex.core.query.QueryCondition;
import com.mybatisflex.core.query.QueryWrapper;
import org.springframework.stereotype.Component;
import tech.easyflow.ai.entity.DocumentCollection;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
import tech.easyflow.system.enums.CategoryResourceType;
import tech.easyflow.system.enums.VisibilityScope;
import tech.easyflow.system.service.CategoryPermissionService;
import tech.easyflow.system.service.SysDeptService;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.Collections;
import java.util.Set;

import static tech.easyflow.ai.entity.table.DocumentCollectionTableDef.DOCUMENT_COLLECTION;

@Component
public class KnowledgeVisibilityQueryHelper {

    @Resource
    private CategoryPermissionService categoryPermissionService;

    @Resource
    private SysDeptService sysDeptService;

    public KnowledgeReadAccessSnapshot getCurrentReadSnapshot() {
        RoleCategoryAccessSnapshot categoryAccess = categoryPermissionService.getCurrentAccess(CategoryResourceType.KNOWLEDGE.getCode());
        if (categoryAccess.isSuperAdmin()) {
            return new KnowledgeReadAccessSnapshot(categoryAccess, Collections.emptySet());
        }
        LoginAccount loginAccount = SaTokenUtil.getLoginAccount();
        Set<BigInteger> deptIds = loginAccount == null
                ? Collections.emptySet()
                : sysDeptService.getSelfAndAncestorDeptIds(loginAccount.getDeptId());
        return new KnowledgeReadAccessSnapshot(categoryAccess, deptIds);
    }

    public void applyReadableAccess(QueryWrapper queryWrapper) {
        applyReadableAccess(queryWrapper, getCurrentReadSnapshot());
    }

    public void applyReadableAccess(QueryWrapper queryWrapper, KnowledgeReadAccessSnapshot snapshot) {
        if (snapshot.isSuperAdmin()) {
            return;
        }
        BigInteger accountId = snapshot.getAccountId();
        if (accountId == null) {
            queryWrapper.eq("id", BigInteger.valueOf(-1));
            return;
        }
        QueryCondition ownerCondition = DOCUMENT_COLLECTION.CREATED_BY.eq(accountId);
        if (snapshot.isRestricted() && snapshot.getCategoryIds().isEmpty()) {
            queryWrapper.and(ownerCondition);
            return;
        }
        QueryCondition visibilityCondition = DOCUMENT_COLLECTION.VISIBILITY_SCOPE.eq(VisibilityScope.PUBLIC.name());
        if (!snapshot.getReadableDeptIds().isEmpty()) {
            visibilityCondition = visibilityCondition.or(
                    DOCUMENT_COLLECTION.VISIBILITY_SCOPE.eq(VisibilityScope.DEPT.name())
                            .and(DOCUMENT_COLLECTION.DEPT_ID.in(snapshot.getReadableDeptIds()))
            );
        }
        QueryCondition readableCondition = visibilityCondition;
        if (snapshot.isRestricted()) {
            readableCondition = DOCUMENT_COLLECTION.CATEGORY_ID.in(snapshot.getCategoryIds()).and(visibilityCondition);
        }
        queryWrapper.and(ownerCondition.or(readableCondition));
    }

    public boolean canRead(DocumentCollection collection) {
        return canRead(collection, getCurrentReadSnapshot());
    }

    public boolean canRead(DocumentCollection collection, KnowledgeReadAccessSnapshot snapshot) {
        if (collection == null) {
            return false;
        }
        if (snapshot.isSuperAdmin()) {
            return true;
        }
        BigInteger accountId = snapshot.getAccountId();
        if (accountId != null && accountId.equals(collection.getCreatedBy())) {
            return true;
        }
        if (snapshot.isRestricted() && (collection.getCategoryId() == null || !snapshot.getCategoryIds().contains(collection.getCategoryId()))) {
            return false;
        }
        VisibilityScope scope = VisibilityScope.fromOrDefault(collection.getVisibilityScope(), VisibilityScope.PRIVATE);
        if (VisibilityScope.PUBLIC == scope) {
            return true;
        }
        return VisibilityScope.DEPT == scope
                && collection.getDeptId() != null
                && snapshot.getReadableDeptIds().contains(collection.getDeptId());
    }
}
