import 'package:freezed_annotation/freezed_annotation.dart'; part 'company_hierarchy.freezed.dart'; /// Company 계층 구조 도메인 엔티티 @freezed class CompanyHierarchy with _$CompanyHierarchy { const CompanyHierarchy._(); const factory CompanyHierarchy({ required String id, required String name, String? parentId, String? parentName, @Default([]) List children, @Default(0) int level, @Default('') String fullPath, @Default(false) bool isExpanded, @Default(0) int totalDescendants, }) = _CompanyHierarchy; /// 계층 구조에서 특정 회사 찾기 CompanyHierarchy? findCompany(String companyId) { if (id == companyId) { return this; } for (final child in children) { final found = child.findCompany(companyId); if (found != null) { return found; } } return null; } /// 모든 자손 회사 ID 목록 가져오기 List getAllDescendantIds() { final ids = []; for (final child in children) { ids.add(child.id); ids.addAll(child.getAllDescendantIds()); } return ids; } /// 특정 회사가 자손인지 확인 bool hasDescendant(String companyId) { return getAllDescendantIds().contains(companyId); } /// 계층 구조의 최대 깊이 계산 int getMaxDepth() { if (children.isEmpty) { return level; } return children .map((child) => child.getMaxDepth()) .reduce((max, depth) => depth > max ? depth : max); } /// 순환 참조 검증 bool wouldCreateCycle(String newParentId) { // 자기 자신을 부모로 설정하려는 경우 if (id == newParentId) { return true; } // 자손을 부모로 설정하려는 경우 if (hasDescendant(newParentId)) { return true; } return false; } /// 계층 경로 생성 String buildPath(String separator) { final parts = fullPath.split('/').where((p) => p.isNotEmpty).toList(); return parts.join(separator); } /// 평면 리스트로 변환 (트리 구조 → 플랫 리스트) List flatten() { final flatList = [this]; for (final child in children) { flatList.addAll(child.flatten()); } return flatList; } /// 계층 구조 통계 Map getStatistics() { final flat = flatten(); return { 'totalCompanies': flat.length, 'maxDepth': getMaxDepth(), 'directChildren': children.length, 'totalDescendants': totalDescendants, 'levels': _getLevelDistribution(flat), }; } Map _getLevelDistribution(List companies) { final distribution = {}; for (final company in companies) { distribution[company.level] = (distribution[company.level] ?? 0) + 1; } return distribution; } } /// 계층 구조 검증 결과 @freezed class HierarchyValidationResult with _$HierarchyValidationResult { const factory HierarchyValidationResult({ required bool isValid, @Default('') String message, @Default([]) List errors, @Default([]) List warnings, }) = _HierarchyValidationResult; factory HierarchyValidationResult.valid() => const HierarchyValidationResult( isValid: true, message: 'Hierarchy is valid', ); factory HierarchyValidationResult.invalid({ required String message, List errors = const [], List warnings = const [], }) => HierarchyValidationResult( isValid: false, message: message, errors: errors, warnings: warnings, ); }