import 'dart:async';

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_state.dart';
import 'package:syncrow_web/pages/space_tree/model/pagination_model.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/community_model.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/space_model.dart';
import 'package:syncrow_web/services/space_mana_api.dart';

class SpaceTreeBloc extends Bloc<SpaceTreeEvent, SpaceTreeState> {
  SpaceTreeBloc() : super(const SpaceTreeState()) {
    on<InitialEvent>(_fetchSpaces);
    on<OnCommunityExpanded>(_onCommunityExpanded);
    on<OnSpaceExpanded>(_onSpaceExpanded);
    on<OnCommunitySelected>(_onCommunitySelected);
    on<OnSpaceSelected>(_onSpaceSelected);
    on<SearchQueryEvent>(_onSearch);
    on<ClearAllData>(_clearAllData);
    on<ClearCachedData>(_clearCachedData);
    on<OnCommunityAdded>(_onCommunityAdded);
    on<OnCommunityUpdated>(_onCommunityUpdate);
    on<PaginationEvent>(_fetchPaginationSpaces);
    on<DebouncedSearchEvent>(_onDebouncedSearch);
    on<SpaceTreeClearSelectionEvent>(_onSpaceTreeClearSelectionEvent);
    on<AnalyticsClearAllSpaceTreeSelectionsEvent>(
      _onAnalyticsClearAllSpaceTreeSelectionsEvent,
    );
  }
  Timer _timer = Timer(const Duration(microseconds: 0), () {});

  void _onCommunityUpdate(
    OnCommunityUpdated event,
    Emitter<SpaceTreeState> emit,
  ) async {
    emit(SpaceTreeLoadingState());

    try {
      final updatedCommunity = event.updatedCommunity;
      final updatedCommunities = List<CommunityModel>.from(state.communityList);

      final index = updatedCommunities
          .indexWhere((community) => community.uuid == updatedCommunity.uuid);

      if (index != -1) {
        updatedCommunities[index] = updatedCommunity;
        emit(state.copyWith(communitiesList: updatedCommunities));
      } else {
        emit(const SpaceTreeErrorState('Community not found in the list.'));
      }
    } catch (e) {
      emit(SpaceTreeErrorState('Error updating community: $e'));
    }
  }

  _fetchSpaces(InitialEvent event, Emitter<SpaceTreeState> emit) async {
    emit(SpaceTreeLoadingState());
    try {
      final projectUuid = await ProjectManager.getProjectUUID() ?? '';

      PaginationModel paginationModel = await CommunitySpaceManagementApi()
          .fetchCommunitiesAndSpaces(projectId: projectUuid, page: 1);

      // List<CommunityModel> updatedCommunities = await Future.wait(
      //   communities.map((community) async {
      // List<SpaceModel> spaces =
      //     await CommunitySpaceManagementApi().getSpaceHierarchy(community.uuid, projectUuid);

      //     return CommunityModel(
      //       uuid: community.uuid,
      //       createdAt: community.createdAt,
      //       updatedAt: community.updatedAt,
      //       name: community.name,
      //       description: community.description,
      //       spaces: spaces,
      //       region: community.region,
      //     );
      //   }).toList(),
      // );

      emit(state.copyWith(
          communitiesList: paginationModel.communities,
          expandedCommunity: [],
          expandedSpaces: [],
          paginationModel: paginationModel));
    } catch (e) {
      emit(SpaceTreeErrorState('Error loading communities and spaces: $e'));
    }
  }

  _fetchPaginationSpaces(PaginationEvent event, Emitter<SpaceTreeState> emit) async {
    emit(state.copyWith(paginationIsLoading: true));
    PaginationModel paginationModel = event.paginationModel;
    List<CommunityModel> communities = List<CommunityModel>.from(event.communities);
    try {
      if (paginationModel.hasNext && state.searchQuery.isEmpty) {
        final projectUuid = await ProjectManager.getProjectUUID() ?? '';

        paginationModel = await CommunitySpaceManagementApi()
            .fetchCommunitiesAndSpaces(
                projectId: projectUuid,
                page: paginationModel.pageNum,
                search: state.searchQuery);

        communities.addAll(paginationModel.communities);
      }
    } catch (e) {
      emit(SpaceTreeErrorState('Error loading communities and spaces: $e'));
    }
    emit(state.copyWith(
        communitiesList: communities,
        paginationModel: paginationModel,
        paginationIsLoading: false));
  }

  void _onCommunityAdded(
      OnCommunityAdded event, Emitter<SpaceTreeState> emit) async {
    final updatedCommunities = List<CommunityModel>.from(state.communityList);
    updatedCommunities.add(event.newCommunity);

    emit(state.copyWith(communitiesList: updatedCommunities));
  }

  _onCommunityExpanded(
      OnCommunityExpanded event, Emitter<SpaceTreeState> emit) async {
    try {
      List<String> updatedExpandedCommunityList =
          List.from(state.expandedCommunities);

      if (updatedExpandedCommunityList.contains(event.communityId)) {
        updatedExpandedCommunityList.remove(event.communityId);
      } else {
        updatedExpandedCommunityList.add(event.communityId);
      }

      emit(state.copyWith(
        expandedCommunity: updatedExpandedCommunityList,
      ));
    } catch (e) {
      emit(const SpaceTreeErrorState('Something went wrong'));
    }
  }

  _onSpaceExpanded(OnSpaceExpanded event, Emitter<SpaceTreeState> emit) async {
    try {
      List<String> updatedExpandedSpacesList = List.from(state.expandedSpaces);

      if (updatedExpandedSpacesList.contains(event.spaceId)) {
        updatedExpandedSpacesList.remove(event.spaceId);
      } else {
        updatedExpandedSpacesList.add(event.spaceId);
      }

      emit(state.copyWith(expandedSpaces: updatedExpandedSpacesList));
    } catch (e) {
      emit(const SpaceTreeErrorState('Something went wrong'));
    }
  }

  _onCommunitySelected(
      OnCommunitySelected event, Emitter<SpaceTreeState> emit) async {
    try {
      List<String> updatedSelectedCommunities =
          List.from(state.selectedCommunities.toSet().toList());
      List<String> updatedSelectedSpaces =
          List.from(state.selectedSpaces.toSet().toList());
      List<String> updatedSoldChecks = List.from(state.soldCheck.toSet().toList());
      Map<String, List<String>> communityAndSpaces =
          Map.from(state.selectedCommunityAndSpaces);
      List<String> selectedSpacesInCommunity =
          communityAndSpaces[event.communityId] ?? [];

      List<String> childrenIds = _getAllChildIds(event.children);

      if (!updatedSelectedCommunities.contains(event.communityId)) {
        // Select the community and all its children
        updatedSelectedCommunities.add(event.communityId);
        updatedSelectedSpaces.addAll(childrenIds);
        selectedSpacesInCommunity.addAll(childrenIds);
      } else {
        // Unselect the community and all its children
        updatedSelectedCommunities.remove(event.communityId);
        updatedSelectedSpaces.removeWhere(childrenIds.contains);
        updatedSoldChecks.removeWhere(childrenIds.contains);
        selectedSpacesInCommunity.removeWhere(childrenIds.contains);
      }

      communityAndSpaces[event.communityId] = selectedSpacesInCommunity;

      emit(state.copyWith(
          selectedCommunities: updatedSelectedCommunities,
          selectedSpaces: updatedSelectedSpaces,
          soldCheck: updatedSoldChecks,
          selectedCommunityAndSpaces: communityAndSpaces));
    } catch (e) {
      emit(const SpaceTreeErrorState('Something went wrong'));
    }
  }

  _onSpaceSelected(OnSpaceSelected event, Emitter<SpaceTreeState> emit) async {
    try {
      List<String> updatedSelectedCommunities =
          List.from(state.selectedCommunities.toSet().toList());
      List<String> updatedSelectedSpaces =
          List.from(state.selectedSpaces.toSet().toList());
      List<String> updatedSoldChecks = List.from(state.soldCheck.toSet().toList());
      Map<String, List<String>> communityAndSpaces =
          Map.from(state.selectedCommunityAndSpaces);

      List<String> selectedSpacesInCommunity =
          communityAndSpaces[event.communityModel.uuid] ?? [];

      List<String> childrenIds = _getAllChildIds(event.children);
      bool isChildSelected = false;

      for (String id in childrenIds) {
        if (updatedSelectedSpaces.contains(id)) {
          isChildSelected = true;
        }
      }

      if (!updatedSelectedSpaces.contains(event.spaceId) &&
          !updatedSoldChecks.contains(event.spaceId)) {
        // First click: Select the space and all its children
        updatedSelectedSpaces.add(event.spaceId);
        updatedSelectedCommunities.add(event.communityModel.uuid);
        selectedSpacesInCommunity.add(event.spaceId);

        if (childrenIds.isNotEmpty) {
          updatedSelectedSpaces.addAll(childrenIds);
          selectedSpacesInCommunity.addAll(childrenIds);
        }

        List<String> spaces =
            _getThePathToChild(event.communityModel.uuid, event.spaceId);
        for (String space in spaces) {
          if (!updatedSelectedSpaces.contains(space) &&
              !updatedSoldChecks.contains(space)) {
            updatedSoldChecks.add(space);
          }
        }
      } else if (!updatedSoldChecks.contains(event.spaceId) &&
          childrenIds.isNotEmpty &&
          isChildSelected) {
        // Second click: Unselect space but keep children
        selectedSpacesInCommunity.remove(event.spaceId);
        updatedSelectedSpaces.remove(event.spaceId);
        updatedSoldChecks.add(event.spaceId);
      } else {
        // Third click: Unselect space and all its children
        selectedSpacesInCommunity.remove(event.spaceId);
        updatedSelectedSpaces.remove(event.spaceId);
        if (childrenIds.isNotEmpty) {
          updatedSelectedSpaces.removeWhere(childrenIds.contains);
          updatedSoldChecks.removeWhere(childrenIds.contains);
          selectedSpacesInCommunity.removeWhere(childrenIds.contains);
        }
        updatedSoldChecks.remove(event.spaceId);

        List<String> parents =
            _getThePathToChild(event.communityModel.uuid, event.spaceId)
                .toSet()
                .toList();

        if (updatedSelectedSpaces.isEmpty) {
          updatedSoldChecks.removeWhere(parents.contains);
          updatedSelectedCommunities.remove(event.communityModel.uuid);
        } else {
          // Check if any parent has selected children
          for (String space in parents) {
            if (!_noChildrenSelected(
                event.communityModel, space, updatedSelectedSpaces, parents)) {
              updatedSoldChecks.remove(space);
            }
          }

          if (!_anySpacesSelectedInCommunity(
              event.communityModel, updatedSelectedSpaces, updatedSoldChecks)) {
            updatedSelectedCommunities.remove(event.communityModel.uuid);
          }
        }
      }

      communityAndSpaces[event.communityModel.uuid] = selectedSpacesInCommunity;

      emit(state.copyWith(
          selectedCommunities: updatedSelectedCommunities.toSet().toList(),
          selectedSpaces: updatedSelectedSpaces,
          soldCheck: updatedSoldChecks,
          selectedCommunityAndSpaces: communityAndSpaces));
    } catch (e) {
      emit(const SpaceTreeErrorState('Something went wrong'));
    }
  }

  _noChildrenSelected(CommunityModel community, String spaceId,
      List<String> selectedSpaces, List<String> parents) {
    if (selectedSpaces.contains(spaceId)) {
      return true;
    }

    List<SpaceModel> children = _getAllChildSpaces(community.spaces);
    for (var child in children) {
      if (spaceId == child.uuid) {
        List<String> ids = _getAllChildIds(child.children);
        for (var id in ids) {
          if (selectedSpaces.contains(id)) {
            return true;
          }
        }
      }
    }

    return false;
  }

  _onSearch(SearchQueryEvent event, Emitter<SpaceTreeState> emit) async {
    try {
      const duration = Duration(seconds: 1);
      if (_timer.isActive) {
        _timer.cancel(); // clear timer
      }
      _timer =
          Timer(duration, () async => add(DebouncedSearchEvent(event.searchQuery)));

      // List<CommunityModel> communities = List.from(state.communityList);
      // List<CommunityModel> filteredCommunity = [];

      // Filter communities and expand only those that match the query
      // filteredCommunity = communities.where((community) {
      //   final containsQueryInCommunity =
      //       community.name.toLowerCase().contains(event.searchQuery.toLowerCase());
      //   final containsQueryInSpaces =
      //       community.spaces.any((space) => _containsQuery(space, event.searchQuery.toLowerCase()));

      //   return containsQueryInCommunity || containsQueryInSpaces;
      // }).toList();

      // emit(state.copyWith(
      //     filteredCommunity: filteredCommunity,
      //     isSearching: event.searchQuery.isNotEmpty,
      //     searchQuery: event.searchQuery));
    } catch (e) {
      emit(const SpaceTreeErrorState('Something went wrong'));
    }
  }

  _onDebouncedSearch(
      DebouncedSearchEvent event, Emitter<SpaceTreeState> emit) async {
    emit(state.copyWith(
      isSearching: true,
    ));
    PaginationModel paginationModel = const PaginationModel.emptyConstructor();
    try {
      final projectUuid = await ProjectManager.getProjectUUID() ?? '';

      paginationModel = await CommunitySpaceManagementApi()
          .fetchCommunitiesAndSpaces(
              projectId: projectUuid, page: 1, search: event.searchQuery);
    } catch (_) {}

    emit(state.copyWith(
        filteredCommunity: paginationModel.communities,
        isSearching: false,
        searchQuery: event.searchQuery));
  }

  _clearAllData(ClearAllData event, Emitter<SpaceTreeState> emit) async {
    try {
      emit(state.copyWith(
          communitiesList: [],
          filteredCommunity: [],
          isSearching: false,
          soldCheck: [],
          selectedSpaces: [],
          selectedCommunities: [],
          selectedCommunityAndSpaces: {},
          searchQuery: '',
          expandedSpaces: [],
          expandedCommunity: []));
    } catch (e) {
      emit(const SpaceTreeErrorState('Something went wrong'));
    }
  }

  _clearCachedData(ClearCachedData event, Emitter<SpaceTreeState> emit) async {
    try {
      emit(state.copyWith(
          communitiesList: state.communityList,
          filteredCommunity: [],
          isSearching: false,
          soldCheck: [],
          selectedSpaces: [],
          selectedCommunities: [],
          selectedCommunityAndSpaces: {},
          searchQuery: '',
          expandedSpaces: [],
          expandedCommunity: []));
    } catch (e) {
      emit(const SpaceTreeErrorState('Something went wrong'));
    }
  }

  // Helper function to determine if any space or its children match the search query
  // bool _containsQuery(SpaceModel space, String query) {
  //   final matchesSpace = space.name.toLowerCase().contains(query);
  //   final matchesChildren =
  //       space.children.any((child) => _containsQuery(child, query)); // Recursive check for children

  //   return matchesSpace || matchesChildren;
  // }

  List<String> _getAllChildIds(List<SpaceModel> spaces) {
    List<String> ids = [];
    for (var child in spaces) {
      ids.add(child.uuid!);
      ids.addAll(_getAllChildIds(child.children));
    }
    return ids.toSet().toList();
  }

  List<SpaceModel> _getAllChildSpaces(List<SpaceModel> spaces) {
    List<SpaceModel> children = [];
    for (var child in spaces) {
      children.add(child);
      children.addAll(_getAllChildSpaces(child.children));
    }
    return children;
  }

  bool _anySpacesSelectedInCommunity(CommunityModel community,
      List<String> selectedSpaces, List<String> partialCheckedList) {
    bool result = false;
    List<String> ids = _getAllChildIds(community.spaces);
    for (var id in ids) {
      result = selectedSpaces.contains(id) || partialCheckedList.contains(id);
      if (result) {
        return result;
      }
    }
    return result;
  }

  List<String> _getThePathToChild(String communityId, String selectedSpaceId) {
    List<String> ids = [];
    final communityDataSource =
        state.searchQuery.isNotEmpty ? state.filteredCommunity : state.communityList;
    for (final community in communityDataSource) {
      if (community.uuid == communityId) {
        for (final space in community.spaces) {
          final list = <String>[];
          list.add(space.uuid!);
          ids = _getAllParentsIds(space, selectedSpaceId, List.from(list));
          if (ids.isNotEmpty) {
            return ids;
          }
        }
      }
    }
    return ids;
  }

  List<String> _getAllParentsIds(
      SpaceModel child, String spaceId, List<String> listIds) {
    List<String> ids = listIds;

    ids.add(child.uuid ?? '');

    if (child.uuid == spaceId) {
      return ids;
    }

    if (child.children.isNotEmpty) {
      for (var space in child.children) {
        var result = _getAllParentsIds(space, spaceId, List.from(ids));
        if (result.isNotEmpty) {
          return result;
        }
      }
    }

    ids.removeLast();
    return [];
  }

  void _onSpaceTreeClearSelectionEvent(
    SpaceTreeClearSelectionEvent event,
    Emitter<SpaceTreeState> emit,
  ) async {
    emit(
      state.copyWith(
        selectedCommunities: [],
        selectedCommunityAndSpaces: {},
        selectedSpaces: [],
      ),
    );
  }

  void _onAnalyticsClearAllSpaceTreeSelectionsEvent(
    AnalyticsClearAllSpaceTreeSelectionsEvent event,
    Emitter<SpaceTreeState> emit,
  ) async {
    emit(
      state.copyWith(
        selectedCommunities: [],
        selectedCommunityAndSpaces: {},
        selectedSpaces: [],
        soldCheck: [],
      ),
    );
  }

  @override
  Future<void> close() async {
    _timer.cancel();
    super.close();
  }
}
