import type { CircuitGroupSnapshot, } from "../../domain/models/circuit-group-structure-project-command.model"; import { circuitGroupCategoryNumbers, circuitGroupCategoryLabels, type CircuitGroupCategory, } from "../../shared/constants/circuit-group"; import type { CircuitTreeSectionDto } from "../types"; import type { CircuitGroupReorderAssignment, } from "../../domain/models/circuit-group-structure-project-command.model"; export function toCircuitGroupSnapshot( section: CircuitTreeSectionDto, circuitListId: string ): CircuitGroupSnapshot { if (!section.category || !section.groupNumber) { throw new Error("Der Bereich ist keine verwaltbare Stromkreisgruppe."); } return { id: section.id, circuitListId, key: section.key, displayName: section.displayName, prefix: section.prefix, sortOrder: section.sortOrder, category: section.category, groupNumber: section.groupNumber, }; } export function buildNewCircuitGroupSnapshot(input: { id: string; circuitListId: string; category: CircuitGroupCategory; displayName?: string; sections: readonly CircuitTreeSectionDto[]; }): CircuitGroupSnapshot { const groupedSections = input.sections.filter( (section): section is CircuitTreeSectionDto & { category: CircuitGroupCategory; groupNumber: number; } => Boolean(section.category && section.groupNumber) ); const groupNumber = Math.max( 0, ...groupedSections .filter((section) => section.category === input.category) .map((section) => section.groupNumber) ) + 1; return { id: input.id, circuitListId: input.circuitListId, key: `${input.category}_${groupNumber}`, displayName: input.displayName?.trim() || `${circuitGroupCategoryLabels[input.category]} ${groupNumber}`, prefix: `-${circuitGroupCategoryNumbers[input.category]}F${groupNumber}.`, sortOrder: getNewGroupSortOrder( input.category, groupedSections ), category: input.category, groupNumber, }; } export function renameCircuitGroupSnapshot( expected: CircuitGroupSnapshot, displayName: string ): CircuitGroupSnapshot { return { ...expected, displayName: displayName.trim() }; } export function canDeleteCircuitGroup( section: CircuitTreeSectionDto ): boolean { return section.circuits.length === 0 && section.components.length === 0; } export function buildCircuitGroupReorderAssignments( sections: readonly CircuitTreeSectionDto[], groupId: string, direction: -1 | 1 ): CircuitGroupReorderAssignment[] | null { const current = sections.find((section) => section.id === groupId); if (!current?.category) { return null; } const categoryGroups = sections .filter((section) => section.category === current.category) .sort( (left, right) => left.sortOrder - right.sortOrder || left.id.localeCompare(right.id) ); const currentIndex = categoryGroups.findIndex( (section) => section.id === groupId ); const target = categoryGroups[currentIndex + direction]; if (!target) { return null; } return sections.map((section) => ({ groupId: section.id, expectedSortOrder: section.sortOrder, targetSortOrder: section.id === current.id ? target.sortOrder : section.id === target.id ? current.sortOrder : section.sortOrder, })); } function getNewGroupSortOrder( category: CircuitGroupCategory, sections: readonly (CircuitTreeSectionDto & { category: CircuitGroupCategory; groupNumber: number; })[] ): number { const ordered = [...sections].sort( (left, right) => left.sortOrder - right.sortOrder ); const sameCategory = ordered.filter( (section) => section.category === category ); const previous = sameCategory[sameCategory.length - 1]; if (!previous) { return ordered.length === 0 ? 10 : Math.max(...ordered.map((section) => section.sortOrder)) + 10; } const next = ordered.find( (section) => section.sortOrder > previous.sortOrder ); return next ? previous.sortOrder + (next.sortOrder - previous.sortOrder) / 2 : previous.sortOrder + 10; }