export interface CompoundMemberLike { id: number; parentStructure?: number | { id: number } | null; constructionStatus?: string | null; storageUsedKg?: number | null; storageCapacityKg?: number | null; } export function compoundParentId(member: CompoundMemberLike): number | null { const parent = member.parentStructure; if (parent === null || parent === undefined) return null; return typeof parent === "object" ? parent.id : parent; } export function isOperationalMember(member: CompoundMemberLike): boolean { return (member.constructionStatus ?? "complete") === "complete"; } /** * Compound storage pooling: the hub's totals cover itself plus its operational * children. Building or awaiting-materials children contribute nothing yet. An * uncapped member (null capacity) makes the whole compound uncapped. */ export function aggregateCompoundStorage( hub: CompoundMemberLike, children: CompoundMemberLike[], ): { storageUsedKg: number; storageCapacityKg: number | null } { let used = hub.storageUsedKg ?? 0; let capacity: number | null = hub.storageCapacityKg ?? null; for (const child of children) { if (!isOperationalMember(child)) continue; used += child.storageUsedKg ?? 0; const childCap = child.storageCapacityKg; if (childCap === null || childCap === undefined) capacity = null; else if (capacity !== null) capacity += childCap; } return { storageUsedKg: used, storageCapacityKg: capacity }; }