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(_onSelectCommunity); on(_onCommunityDelete); on(_onUpdateCommunity); on(_onSaveSpaces); on(_onFetchProducts); on(_onSelectSpace); on(_onNewCommunity); } 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 _onloadProducts() async { if (_cachedProducts == null) { final products = await _productApi.fetchProducts(); _cachedProducts = products; } } void _onFetchProducts( FetchProductsEvent event, Emitter emit, ) async { try { _onloadProducts(); } catch (e) { emit(SpaceManagementError('Error fetching products: $e')); } } Future> _fetchSpacesForCommunity( String communityUuid) async { return await _api.getSpaceHierarchy(communityUuid); } void _onNewCommunity( NewCommunityEvent event, Emitter emit, ) { try { if (event.communities.isEmpty) { emit(const SpaceManagementError('No communities provided.')); return; } emit(BlankState( communities: event.communities, products: _cachedProducts ?? [], )); } catch (error) { emit(SpaceManagementError('Error loading communities: $error')); } } void _onLoadCommunityAndSpaces( LoadCommunityAndSpacesEvent event, Emitter emit, ) async { emit(SpaceManagementLoading()); try { _onloadProducts(); List communities = await _api.fetchCommunities(); List updatedCommunities = await Future.wait( communities.map((community) async { List spaces = await _fetchSpacesForCommunity(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 || previousState is BlankState) { final prevCommunities = List.from( (previousState as dynamic).communities, ); final updatedCommunities = prevCommunities..add(newCommunity); emit(SpaceManagementLoaded( communities: updatedCommunities, products: _cachedProducts ?? [], selectedCommunity: newCommunity, selectedSpace: null)); } } else { emit(const SpaceManagementError('Error creating community')); } } catch (e) { emit(SpaceManagementError('Error creating community: $e')); } } void _onSelectCommunity( SelectCommunityEvent event, Emitter emit, ) async { _handleCommunitySpaceStateUpdate( emit: emit, selectedCommunity: event.selectedCommunity, selectedSpace: null, ); } void _onSelectSpace( SelectSpaceEvent event, Emitter emit, ) { _handleCommunitySpaceStateUpdate( emit: emit, selectedCommunity: event.selectedCommunity, selectedSpace: event.selectedSpace, ); } void _handleCommunitySpaceStateUpdate({ required Emitter emit, CommunityModel? selectedCommunity, SpaceModel? selectedSpace, }) { final previousState = state; emit(SpaceManagementLoading()); try { if (previousState is SpaceManagementLoaded || previousState is BlankState) { final communities = List.from( (previousState as dynamic).communities, ); emit(SpaceManagementLoaded( communities: communities, products: _cachedProducts ?? [], selectedCommunity: selectedCommunity, selectedSpace: selectedSpace, )); } } catch (e) { emit(SpaceManagementError('Error updating state: $e')); } } void _onSaveSpaces( SaveSpacesEvent event, Emitter emit, ) async { final previousState = state; emit(SpaceManagementLoading()); try { final updatedSpaces = await saveSpacesHierarchically(event.spaces, event.communityUuid); final allSpaces = await _fetchSpacesForCommunity(event.communityUuid); emit(SpaceCreationSuccess(spaces: updatedSpaces)); if (previousState is SpaceManagementLoaded) { _updateLoadedState( previousState, allSpaces, event.communityUuid, emit, ); } else { add(LoadCommunityAndSpacesEvent()); } } catch (e) { emit(SpaceManagementError('Error saving spaces: $e')); if (previousState is SpaceManagementLoaded) { emit(previousState); } } } void _updateLoadedState( SpaceManagementLoaded previousState, List allSpaces, String communityUuid, Emitter emit, ) { final communities = List.from(previousState.communities); for (var community in communities) { if (community.uuid == communityUuid) { community.spaces = allSpaces; emit(SpaceManagementLoaded( communities: communities, products: _cachedProducts ?? [], selectedCommunity: community, selectedSpace: null, )); return; } } } 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 { 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 } }