package tech.easyflow.ai.permission;

import org.junit.Assert;
import org.junit.Test;
import tech.easyflow.ai.entity.DocumentCollection;
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;

import java.math.BigInteger;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;

public class KnowledgeVisibilityQueryHelperTest {

    private final KnowledgeVisibilityQueryHelper helper = new KnowledgeVisibilityQueryHelper();

    @Test
    public void canRead_shouldAllowCreatorForPrivateKnowledge() {
        DocumentCollection collection = buildCollection(BigInteger.valueOf(11), BigInteger.valueOf(21), "PRIVATE");
        KnowledgeReadAccessSnapshot snapshot = buildSnapshot(
                BigInteger.valueOf(11),
                false,
                false,
                Collections.emptySet(),
                Collections.emptySet()
        );

        Assert.assertTrue(helper.canRead(collection, snapshot));
    }

    @Test
    public void canRead_shouldRejectWhenCategoryNotMatched() {
        DocumentCollection collection = buildCollection(BigInteger.valueOf(11), BigInteger.valueOf(21), "PUBLIC");
        KnowledgeReadAccessSnapshot snapshot = buildSnapshot(
                BigInteger.valueOf(12),
                false,
                false,
                setOf(BigInteger.valueOf(99)),
                Collections.emptySet()
        );

        Assert.assertFalse(helper.canRead(collection, snapshot));
    }

    @Test
    public void canRead_shouldAllowDeptScopedKnowledgeForDescendantUser() {
        DocumentCollection collection = buildCollection(BigInteger.valueOf(11), BigInteger.valueOf(21), "DEPT");
        collection.setDeptId(BigInteger.valueOf(3));
        KnowledgeReadAccessSnapshot snapshot = buildSnapshot(
                BigInteger.valueOf(12),
                false,
                false,
                setOf(BigInteger.valueOf(21)),
                setOf(BigInteger.valueOf(1), BigInteger.valueOf(3), BigInteger.valueOf(9))
        );

        Assert.assertTrue(helper.canRead(collection, snapshot));
    }

    @Test
    public void canRead_shouldRejectDeptScopedKnowledgeWithoutDeptMatch() {
        DocumentCollection collection = buildCollection(BigInteger.valueOf(11), BigInteger.valueOf(21), "DEPT");
        collection.setDeptId(BigInteger.valueOf(7));
        KnowledgeReadAccessSnapshot snapshot = buildSnapshot(
                BigInteger.valueOf(12),
                false,
                false,
                setOf(BigInteger.valueOf(21)),
                setOf(BigInteger.valueOf(1), BigInteger.valueOf(3), BigInteger.valueOf(9))
        );

        Assert.assertFalse(helper.canRead(collection, snapshot));
    }

    @Test
    public void canRead_shouldAllowPublicKnowledgeWhenCategoryMatched() {
        DocumentCollection collection = buildCollection(BigInteger.valueOf(11), BigInteger.valueOf(21), "PUBLIC");
        KnowledgeReadAccessSnapshot snapshot = buildSnapshot(
                BigInteger.valueOf(12),
                false,
                false,
                setOf(BigInteger.valueOf(21)),
                Collections.emptySet()
        );

        Assert.assertTrue(helper.canRead(collection, snapshot));
    }

    private DocumentCollection buildCollection(BigInteger createdBy, BigInteger categoryId, String visibilityScope) {
        DocumentCollection collection = new DocumentCollection();
        collection.setCreatedBy(createdBy);
        collection.setCategoryId(categoryId);
        collection.setVisibilityScope(visibilityScope);
        return collection;
    }

    private KnowledgeReadAccessSnapshot buildSnapshot(BigInteger accountId,
                                                      boolean superAdmin,
                                                      boolean allAccess,
                                                      Set<BigInteger> categoryIds,
                                                      Set<BigInteger> deptIds) {
        RoleCategoryAccessSnapshot accessSnapshot = new RoleCategoryAccessSnapshot(
                "KNOWLEDGE",
                accountId,
                superAdmin,
                allAccess,
                categoryIds
        );
        return new KnowledgeReadAccessSnapshot(accessSnapshot, deptIds);
    }

    private Set<BigInteger> setOf(BigInteger... values) {
        Set<BigInteger> result = new LinkedHashSet<>();
        Collections.addAll(result, values);
        return result;
    }
}
