import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/spaces_management/model/community_model.dart'; import 'package:syncrow_web/pages/spaces_management/model/product_model.dart'; import 'package:syncrow_web/pages/spaces_management/model/space_model.dart'; import 'package:syncrow_web/pages/spaces_management/bloc/space_management_event.dart'; import 'package:syncrow_web/pages/spaces_management/bloc/space_management_state.dart'; import 'package:syncrow_web/services/product_api.dart'; import 'package:syncrow_web/services/space_mana_api.dart'; class SpaceManagementBloc extends Bloc { final CommunitySpaceManagementApi _api; final ProductApi _productApi; List? _cachedProducts; SpaceManagementBloc(this._api, this._productApi) : super(SpaceManagementInitial()) { on(_onLoadCommunityAndSpaces); on(_onUpdateSpacePosition); on(_onCreateCommunity); on(_onSaveSpaces); on(_onFetchProducts); on(_onCommunityDelete); on(_onUpdateCommunity); } void _onUpdateCommunity( UpdateCommunityEvent event, Emitter emit, ) async { final previousState = state; try { emit(SpaceManagementLoading()); final success = await _api.updateCommunity(event.communityUuid, event.name); if (success) { if (previousState is SpaceManagementLoaded) { final updatedCommunities = List.from(previousState.communities); for(var community in updatedCommunities){ if(community.uuid == event.communityUuid){ community.name = event.name; break; } } emit(SpaceManagementLoaded( communities: updatedCommunities, products: previousState.products, selectedCommunity: previousState.selectedCommunity, )); } } else { emit(const SpaceManagementError('Failed to update the community.')); } } catch (e) { emit(SpaceManagementError('Error updating community: $e')); } } void _onFetchProducts( FetchProductsEvent event, Emitter emit, ) async { if (_cachedProducts != null) { // Products are already cached, no need to fetch again return; } try { final products = await _productApi.fetchProducts(); _cachedProducts = products; // Cache the products locally } catch (e) { emit(SpaceManagementError('Error fetching products: $e')); } } void _onLoadCommunityAndSpaces( LoadCommunityAndSpacesEvent event, Emitter emit, ) async { emit(SpaceManagementLoading()); try { if (_cachedProducts == null) { final products = await _productApi.fetchProducts(); _cachedProducts = products; } // Fetch all communities List communities = await _api.fetchCommunities(); List updatedCommunities = await Future.wait( communities.map((community) async { List spaces = await _api.getSpaceHierarchy(community.uuid); return CommunityModel( uuid: community.uuid, createdAt: community.createdAt, updatedAt: community.updatedAt, name: community.name, description: community.description, spaces: spaces, // New spaces list region: community.region, ); }).toList(), ); emit(SpaceManagementLoaded(communities: updatedCommunities, products: _cachedProducts ?? [])); } catch (e) { emit(SpaceManagementError('Error loading communities and spaces: $e')); } } void _onCommunityDelete( DeleteCommunityEvent event, Emitter emit, ) async { try { emit(SpaceManagementLoading()); final success = await _api.deleteCommunity(event.communityUuid); if (success) { add(LoadCommunityAndSpacesEvent()); } else { emit(const SpaceManagementError('Failed to delete the community.')); } } catch (e) { // Handle unexpected errors emit(SpaceManagementError('Error saving spaces: $e')); } } void _onUpdateSpacePosition( UpdateSpacePositionEvent event, Emitter emit, ) {} void _onCreateCommunity( CreateCommunityEvent event, Emitter emit, ) async { final previousState = state; emit(SpaceManagementLoading()); try { CommunityModel? newCommunity = await _api.createCommunity(event.name, event.description); if (newCommunity != null) { if (previousState is SpaceManagementLoaded) { final updatedCommunities = List.from(previousState.communities) ..add(newCommunity); emit(SpaceManagementLoaded( communities: updatedCommunities, products: _cachedProducts ?? [], selectedCommunity: newCommunity)); } } else { emit(const SpaceManagementError('Error creating community')); } } catch (e) { emit(SpaceManagementError('Error creating community: $e')); } } void _onSaveSpaces( SaveSpacesEvent event, Emitter emit, ) async { final previousState = state; emit(SpaceManagementLoading()); try { final updatedSpaces = await saveSpacesHierarchically(event.spaces, event.communityUuid); emit(SpaceCreationSuccess(spaces: updatedSpaces)); add(LoadCommunityAndSpacesEvent()); } catch (e) { emit(SpaceManagementError('Error saving spaces: $e')); if (previousState is SpaceManagementLoaded) { emit(previousState); } } } Future> saveSpacesHierarchically( List spaces, String communityUuid) async { final orderedSpaces = flattenHierarchy(spaces); final parentsToDelete = orderedSpaces.where((space) => space.status == SpaceStatus.deleted && (space.parent == null || space.parent?.status != SpaceStatus.deleted)); for (var parent in parentsToDelete) { try { // Ensure parent.uuid is not null before calling the API if (parent.uuid != null) { await _api.deleteSpace(communityUuid, parent.uuid!); } } catch (e) { print( 'Error deleting space ${parent.name} (UUID: ${parent.uuid}, Community UUID: $communityUuid): $e'); rethrow; // Decide whether to stop execution or continue } } for (var space in orderedSpaces) { try { if (space.uuid != null && space.uuid!.isNotEmpty) { final response = await _api.updateSpace( communityId: communityUuid, spaceId: space.uuid!, name: space.name, parentId: space.parent?.uuid, isPrivate: space.isPrivate, position: space.position, icon: space.icon, direction: space.incomingConnection?.direction, products: space.selectedProducts); } else { // Call create if the space does not have a UUID final response = await _api.createSpace( communityId: communityUuid, name: space.name, parentId: space.parent?.uuid, isPrivate: space.isPrivate, position: space.position, icon: space.icon, direction: space.incomingConnection?.direction, products: space.selectedProducts); space.uuid = response?.uuid; } } catch (e) { print('Error creating space ${space.name}: $e'); rethrow; // Stop further execution on failure } } return spaces; } List flattenHierarchy(List spaces) { final result = {}; final topLevelSpaces = spaces.where((space) => space.parent == null); void visit(SpaceModel space) { if (!result.contains(space)) { result.add(space); for (var child in spaces.where((s) => s.parent == space)) { visit(child); } } } for (var space in topLevelSpaces) { visit(space); } for (var space in spaces) { if (!result.contains(space)) { result.add(space); } } return result.toList(); // Convert back to a list } }