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.Workflow;
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.WorkflowTableDef.WORKFLOW;

@Component
public class WorkflowVisibilityQueryHelper {

    @Resource
    private CategoryPermissionService categoryPermissionService;

    @Resource
    private SysDeptService sysDeptService;

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

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

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

    public boolean canRead(Workflow workflow) {
        return canRead(workflow, getCurrentReadSnapshot());
    }

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