package com.njcn.rdms.module.project.service.datascope;

import lombok.Getter;

import java.util.Collections;
import java.util.Set;

/**
 * 数据权限范围：用户在某 objectType（project/product）下能看到哪些对象。
 * 不可变。三态：ALL（看全部，不加 SQL 条件）/ ID_LIST（看具体集合）/ EMPTY（看不到任何）。
 *
 * 设计来源：docs/superpowers/specs/2026-05-14-object-data-scope-design.md 第 3.1 节
 */
@Getter
public final class ObjectDataScope {

    public enum State { ALL, ID_LIST, EMPTY }

    private final State state;
    private final Set<Long>   ids;             // 仅 ID_LIST 时有值
    private final Set<String> directionCodes;  // 仅 ID_LIST 时有值

    private ObjectDataScope(State state, Set<Long> ids, Set<String> directionCodes) {
        this.state = state;
        this.ids = ids == null ? Collections.emptySet() : Collections.unmodifiableSet(ids);
        this.directionCodes = directionCodes == null ? Collections.emptySet() : Collections.unmodifiableSet(directionCodes);
    }

    public static ObjectDataScope all() {
        return new ObjectDataScope(State.ALL, null, null);
    }

    public static ObjectDataScope empty() {
        return new ObjectDataScope(State.EMPTY, null, null);
    }

    public static ObjectDataScope idList(Set<Long> ids, Set<String> directionCodes) {
        boolean idsEmpty = ids == null || ids.isEmpty();
        boolean dcEmpty  = directionCodes == null || directionCodes.isEmpty();
        if (idsEmpty && dcEmpty) {
            return empty();
        }
        return new ObjectDataScope(State.ID_LIST, ids, directionCodes);
    }

    /**
     * 详情入口判定：当前 user 是否能"看到" (objectId, directionCode)。
     * - ALL → true
     * - ID_LIST → ids.contains(objectId) || directionCodes.contains(directionCode)
     * - EMPTY → false
     */
    public boolean contains(Long objectId, String objectDirectionCode) {
        switch (state) {
            case ALL:   return true;
            case EMPTY: return false;
            case ID_LIST:
                if (objectId != null && ids.contains(objectId)) return true;
                if (objectDirectionCode != null && directionCodes.contains(objectDirectionCode)) return true;
                return false;
            default: return false;
        }
    }
}
