/**
 * Object Visibility Membrane — per-object access filtering.
 *
 * Provides a soft membrane where individual items (tasks, docs, events, etc.)
 * can be restricted to specific role tiers. Items default to 'viewer' (visible
 * to everyone) when no visibility is set.
 *
 * Importable by both server and client code.
 */

export type ObjectVisibility = 'viewer' | 'member' | 'moderator' | 'admin';
export const DEFAULT_VISIBILITY: ObjectVisibility = 'viewer';

const ROLE_LEVELS: Record<string, number> = {
	viewer: 0,
	member: 1,
	moderator: 2,
	admin: 3,
};

/** Check if a caller with `callerRole` can see an item with `visibility`. */
export function isVisibleTo(
	visibility: ObjectVisibility | null | undefined,
	callerRole: string,
): boolean {
	const vis = visibility ?? DEFAULT_VISIBILITY;
	const required = ROLE_LEVELS[vis] ?? 0;
	const actual = ROLE_LEVELS[callerRole] ?? 0;
	return actual >= required;
}

/**
 * Filter a Record of items by visibility.
 * @param getVis - accessor for the visibility field (defaults to `item.visibility`)
 */
export function filterByVisibility<T>(
	items: Record<string, T>,
	callerRole: string,
	getVis: (item: T) => ObjectVisibility | null | undefined = (item) =>
		(item as any).visibility,
): Record<string, T> {
	const result: Record<string, T> = {};
	for (const [key, item] of Object.entries(items)) {
		if (isVisibleTo(getVis(item), callerRole)) {
			result[key] = item;
		}
	}
	return result;
}

/**
 * Filter an array of items by visibility.
 * @param getVis - accessor for the visibility field (defaults to `item.visibility`)
 */
export function filterArrayByVisibility<T>(
	items: T[],
	callerRole: string,
	getVis: (item: T) => ObjectVisibility | null | undefined = (item) =>
		(item as any).visibility,
): T[] {
	return items.filter((item) => isVisibleTo(getVis(item), callerRole));
}
