import 'package:bloc/bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
import 'package:syncrow_web/pages/common/custom_dialog.dart';
import 'package:syncrow_web/pages/roles_and_permission/model/edit_user_model.dart';
import 'package:syncrow_web/pages/roles_and_permission/model/role_type_model.dart';
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/model/permission_option_model.dart';
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/model/tree_node_model.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.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';
import 'package:syncrow_web/services/user_permission.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/navigation_service.dart';

class UsersBloc extends Bloc<UsersEvent, UsersState> {
  UsersBloc() : super(UsersInitial()) {
    on<CheckStepStatus>(isCompleteBasicsFun);
    on<LoadCommunityAndSpacesEvent>(_onLoadCommunityAndSpaces);
    on<SearchAnode>(searchTreeNode);
    on<CheckSpacesStepStatus>(isCompleteSpacesFun);
    on<RoleEvent>(_getRolePermission);
    on<PermissionEvent>(_getPermissions);
    on<SearchPermission>(searchRolePermission);
    on<SendInviteUsers>(_sendInvitUser);
    on<ValidateBasicsStep>(_validateBasicsStep);
    on<CheckRoleStepStatus>(isCompleteRoleFun);
    on<CheckEmailEvent>(checkEmail);
    on<GetUserByIdEvent>(getUserById);
    on<ToggleNodeExpansion>(_onToggleNodeExpansion);
    on<ToggleNodeCheck>(_onToggleNodeCheck);
    on<EditInviteUsers>(_editInviteUser);
  }

  void _validateBasicsStep(ValidateBasicsStep event, Emitter<UsersState> emit) {
    if (formKey.currentState?.validate() ?? false) {
      emit(const BasicsStepValidState());
    } else {
      emit(const BasicsStepInvalidState());
    }
  }

  String roleSelected = '';

  final formKey = GlobalKey<FormState>();
  final TextEditingController firstNameController = TextEditingController();
  final TextEditingController lastNameController = TextEditingController();
  final TextEditingController emailController = TextEditingController();
  final TextEditingController phoneController = TextEditingController();
  final TextEditingController jobTitleController = TextEditingController();
  final TextEditingController roleSearchController = TextEditingController();

  bool? isCompleteBasics;
  bool? isCompleteRolePermissions;
  bool? isCompleteSpaces;

  int numberBasics = 0;
  int numberSpaces = 0;
  int numberRole = 0;

  void isCompleteSpacesFun(
      CheckSpacesStepStatus event, Emitter<UsersState> emit) {
    emit(UsersLoadingState());
    var spaceBloc =
        NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>();

    isCompleteSpaces = spaceBloc.state.selectedCommunities.isNotEmpty;
    emit(ChangeStatusSteps());
  }

  void isCompleteRoleFun(CheckRoleStepStatus event, Emitter<UsersState> emit) {
    emit(UsersLoadingState());
    isCompleteRolePermissions = roleSelected != '';
    emit(ChangeStatusSteps());
  }

  Future<List<SpaceModel>> _fetchSpacesForCommunity(
      String communityUuid) async {
    final projectUuid = await ProjectManager.getProjectUUID() ?? '';

    return await CommunitySpaceManagementApi()
        .getSpaceHierarchy(communityUuid, projectUuid);
  }

  List<TreeNode> updatedCommunities = [];
  List<TreeNode> spacesNodes = [];
  List<String> communityIds = [];
  _onLoadCommunityAndSpaces(
      LoadCommunityAndSpacesEvent event, Emitter<UsersState> emit) async {
    try {
      emit(UsersLoadingState());
      final projectUuid = await ProjectManager.getProjectUUID() ?? '';

      List<CommunityModel> communities =
          await CommunitySpaceManagementApi().fetchCommunities(projectUuid);
      communityIds = communities.map((community) => community.uuid).toList();
      updatedCommunities = await Future.wait(
        communities.map((community) async {
          List<SpaceModel> spaces =
              await _fetchSpacesForCommunity(community.uuid);
          spacesNodes = _buildTreeNodes(spaces);
          return TreeNode(
            uuid: community.uuid,
            title: community.name,
            children: spacesNodes,
            isChecked: false,
            isHighlighted: false,
            isExpanded: true,
          );
        }).toList(),
      );
      originalCommunities = updatedCommunities;
      emit(const SpacesLoadedState());
    } catch (e) {
      emit(ErrorState('Error loading communities and spaces: $e'));
    }
  }

// This variable holds the full original list.
  List<TreeNode> originalCommunities = [];

// This variable holds the working list that may be filtered.

// Build tree nodes from your data model.
  List<TreeNode> _buildTreeNodes(List<SpaceModel> spaces) {
    return spaces.map((space) {
      List<TreeNode> childNodes =
          space.children.isNotEmpty ? _buildTreeNodes(space.children) : [];
      return TreeNode(
        uuid: space.uuid!,
        title: space.name,
        isChecked: false,
        isHighlighted: false,
        isExpanded: childNodes.isNotEmpty,
        children: childNodes,
      );
    }).toList();
  }

// Optional helper method to deep clone a TreeNode.
  TreeNode _cloneNode(TreeNode node) {
    return TreeNode(
      uuid: node.uuid,
      title: node.title,
      isChecked: node.isChecked,
      isHighlighted: node.isHighlighted,
      isExpanded: node.isExpanded,
      children: node.children.map(_cloneNode).toList(),
    );
  }

// Clone an entire list of tree nodes.
  List<TreeNode> _cloneNodes(List<TreeNode> nodes) {
    return nodes.map(_cloneNode).toList();
  }

// Your search event handler.
  void searchTreeNode(SearchAnode event, Emitter<UsersState> emit) {
    emit(UsersLoadingState());

    // If the search term is empty, restore the original list.
    if (event.searchTerm!.isEmpty) {
      // Clear any highlights on the restored copy.
      updatedCommunities = _cloneNodes(originalCommunities);
      _clearHighlights(updatedCommunities);
    } else {
      // Start with a fresh clone of the original tree.
      List<TreeNode> freshClone = _cloneNodes(originalCommunities);

      _searchAndHighlightNodes(freshClone, event.searchTerm!);

      updatedCommunities = _filterNodes(freshClone, event.searchTerm!);
    }
    emit(ChangeStatusSteps());
  }

  void _clearHighlights(List<TreeNode> nodes) {
    for (var node in nodes) {
      node.isHighlighted = false;
      if (node.children.isNotEmpty) {
        _clearHighlights(node.children);
      }
    }
  }

  bool _searchAndHighlightNodes(List<TreeNode> nodes, String searchTerm) {
    bool anyMatch = false;
    for (var node in nodes) {
      bool isMatch =
          node.title.toLowerCase().contains(searchTerm.toLowerCase());
      bool childMatch = _searchAndHighlightNodes(node.children, searchTerm);
      node.isHighlighted = isMatch || childMatch;

      anyMatch = anyMatch || node.isHighlighted;
    }
    return anyMatch;
  }

  List<TreeNode> _filterNodes(List<TreeNode> nodes, String searchTerm) {
    List<TreeNode> filteredNodes = [];
    for (var node in nodes) {
      bool isMatch =
          node.title.toLowerCase().contains(searchTerm.toLowerCase());
      List<TreeNode> filteredChildren = _filterNodes(node.children, searchTerm);
      if (isMatch || filteredChildren.isNotEmpty) {
        node.isHighlighted = isMatch;
        node.children = filteredChildren;
        filteredNodes.add(node);
      }
    }
    return filteredNodes;
  }

  // List<TreeNode> _buildTreeNodes(List<SpaceModel> spaces) {
  //   return spaces.map((space) {
  //     List<TreeNode> childNodes =
  //         space.children.isNotEmpty ? _buildTreeNodes(space.children) : [];
  //     return TreeNode(
  //       uuid: space.uuid!,
  //       title: space.name,
  //       isChecked: false,
  //       isHighlighted: false,
  //       isExpanded: childNodes.isNotEmpty,
  //       children: childNodes,
  //     );
  //   }).toList();
  // }

  // void searchTreeNode(SearchAnode event, Emitter<UsersState> emit) {
  //   emit(UsersLoadingState());
  //   if (event.searchTerm!.isEmpty) {
  //     _clearHighlights(updatedCommunities);
  //   } else {
  //     _searchAndHighlightNodes(updatedCommunities, event.searchTerm!);
  //     updatedCommunities = _filterNodes(updatedCommunities, event.searchTerm!);
  //   }
  //   emit(ChangeStatusSteps());
  // }

  // void _clearHighlights(List<TreeNode> nodes) {
  //   for (var node in nodes) {
  //     node.isHighlighted = false;
  //     if (node.children.isNotEmpty) {
  //       _clearHighlights(node.children);
  //     }
  //   }
  // }

  // bool _searchAndHighlightNodes(List<TreeNode> nodes, String searchTerm) {
  //   bool anyMatch = false;
  //   for (var node in nodes) {
  //     bool isMatch =
  //         node.title.toLowerCase().contains(searchTerm.toLowerCase());
  //     bool childMatch = _searchAndHighlightNodes(node.children, searchTerm);
  //     node.isHighlighted = isMatch || childMatch;

  //     anyMatch = anyMatch || node.isHighlighted;
  //   }
  //   return anyMatch;
  // }

  // List<TreeNode> _filterNodes(List<TreeNode> nodes, String searchTerm) {
  //   List<TreeNode> filteredNodes = [];
  //   for (var node in nodes) {
  //     // Check if the current node's title contains the search term.
  //     bool isMatch =
  //         node.title.toLowerCase().contains(searchTerm.toLowerCase());

  //     // Recursively filter the children.
  //     List<TreeNode> filteredChildren = _filterNodes(node.children, searchTerm);

  //     // If the current node is a match or any of its children are, include it.
  //     if (isMatch || filteredChildren.isNotEmpty) {
  //       // Optionally, update any properties (like isHighlighted) if you still need them.
  //       node.isHighlighted = isMatch;
  //       // Replace the children with the filtered ones.
  //       node.children = filteredChildren;
  //       filteredNodes.add(node);
  //     }
  //   }
  //   return filteredNodes;
  // }

  List<String> selectedIds = [];

  List<String> getSelectedIds(List<TreeNode> nodes) {
    List<String> selectedIds = [];
    for (var node in nodes) {
      if (node.isChecked) {
        selectedIds.add(node.uuid);
      }
      if (node.children.isNotEmpty) {
        selectedIds.addAll(getSelectedIds(node.children));
      }
    }
    return selectedIds;
  }

  List<RoleTypeModel> roles = [];
  List<PermissionOption> permissions = [];

  _getRolePermission(RoleEvent event, Emitter<UsersState> emit) async {
    try {
      emit(UsersLoadingState());
      roles = await UserPermissionApi().fetchRoles();
      emit(RolePermissionInitial());
    } catch (e) {
      emit(ErrorState('Error loading communities and spaces: $e'));
    }
  }

  _getPermissions(PermissionEvent event, Emitter<UsersState> emit) async {
    try {
      emit(UsersLoadingState());
      permissions = await UserPermissionApi().fetchPermission(
          event.roleUuid == "" ? roles.first.uuid : event.roleUuid);
      roleSelected = event.roleUuid!;
      emit(RolePermissionInitial());
    } catch (e) {
      emit(ErrorState('Error loading communities and spaces: $e'));
    }
  }

  bool _searchRolePermission(List<PermissionOption> nodes, String searchTerm) {
    bool anyMatch = false;
    for (var node in nodes) {
      bool isMatch =
          node.title.toLowerCase().contains(searchTerm.toLowerCase());
      bool childMatch = _searchRolePermission(node.subOptions, searchTerm);
      node.isHighlighted = isMatch || childMatch;
      anyMatch = anyMatch || node.isHighlighted;
    }
    return anyMatch;
  }

  void _sendInvitUser(SendInviteUsers event, Emitter<UsersState> emit) async {
    try {
      final projectUuid = await ProjectManager.getProjectUUID() ?? '';

      emit(UsersLoadingState());
      // List<String> selectedIds =
      //     getSelectedIds(updatedCommunities).where((id) => !communityIds.contains(id)).toList();

      List<String> selectedSpacesId = getSelectedSpacesIds();
      // List<String> selectedIds = getSelectedIds(updatedCommunities);

      bool res = await UserPermissionApi().sendInviteUser(
          email: emailController.text,
          firstName: firstNameController.text,
          jobTitle: jobTitleController.text,
          lastName: lastNameController.text,
          phoneNumber: phoneController.text,
          roleUuid: roleSelected,
          spaceUuids: selectedSpacesId,
          projectUuid: projectUuid);

      if (res) {
        showCustomDialog(
          barrierDismissible: false,
          context: event.context,
          message: "The invite was sent successfully.",
          iconPath: Assets.deviceNoteIcon,
          title: "Invite Success",
          dialogHeight: MediaQuery.of(event.context).size.height * 0.3,
          actions: <Widget>[
            TextButton(
              onPressed: () {
                Navigator.of(event.context).pop(true);
                Navigator.of(event.context).pop(true);
              },
              child: const Text('OK'),
            ),
          ],
        );
      } else {
        emit(const ErrorState('Failed to send invite.'));
      }
      emit(SaveState());
    } catch (e) {
      emit(ErrorState('Failed to send invite: ${e.toString()}'));
    }
  }

  List<String> getSelectedSpacesIds() {
    List<String> selectedSpacesId = [];
    var spaceBloc =
        NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>();
    for (var community in spaceBloc.state.selectedCommunities) {
      selectedSpacesId
          .addAll(spaceBloc.state.selectedCommunityAndSpaces[community] ?? []);
    }
    return selectedSpacesId;
  }

  _editInviteUser(EditInviteUsers event, Emitter<UsersState> emit) async {
    try {
      emit(UsersLoadingState());
      final projectUuid = await ProjectManager.getProjectUUID() ?? '';

      bool res = await UserPermissionApi().editInviteUser(
          userId: event.userId,
          firstName: firstNameController.text,
          jobTitle: jobTitleController.text,
          lastName: lastNameController.text,
          phoneNumber: phoneController.text,
          roleUuid: roleSelected,
          spaceUuids: getSelectedSpacesIds(),
          projectUuid: projectUuid);
      if (res == true) {
        showCustomDialog(
          barrierDismissible: false,
          context: event.context,
          message: "The invite was sent successfully.",
          iconPath: Assets.deviceNoteIcon,
          title: "Invite Success",
          dialogHeight: MediaQuery.of(event.context).size.height * 0.3,
          actions: <Widget>[
            TextButton(
              onPressed: () {
                Navigator.of(event.context).pop(true);
                Navigator.of(event.context).pop(true);
              },
              child: const Text('OK'),
            ),
          ],
        ).then(
          (value) {},
        );
      } else {
        emit(const ErrorState('Failed to send invite.'));
      }
      emit(SaveState());
    } catch (e) {
      emit(ErrorState('Failed to send invite: ${e.toString()}'));
    }
  }

  void searchRolePermission(SearchPermission event, Emitter<UsersState> emit) {
    emit(UsersLoadingState());
    if (event.searchTerm!.isEmpty) {
      _clearHighlightsRolePermission(permissions);
    } else {
      _searchRolePermission(permissions, event.searchTerm!);
    }
    emit(ChangeStatusSteps());
  }

  String checkEmailValid = '';

  Future<void> checkEmail(
      CheckEmailEvent event, Emitter<UsersState> emit) async {
    emit(UsersLoadingState());
    String?  res = await UserPermissionApi().checkEmail(
      emailController.text,
    );
    checkEmailValid = res!;
    emit(ChangeStatusSteps());
  }

  bool isCompleteBasicsFun(CheckStepStatus event, Emitter<UsersState> emit) {
    emit(UsersLoadingState());
    if (event.isEditUser == false) {
      add(const CheckEmailEvent());
      final emailRegex = RegExp(
        r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
      );
      bool isEmailValid = emailRegex.hasMatch(emailController.text);
      bool isEmailServerValid = checkEmailValid == 'Valid email';
      isCompleteBasics = firstNameController.text.isNotEmpty &&
          lastNameController.text.isNotEmpty &&
          emailController.text.isNotEmpty &&
          isEmailValid &&
          isEmailServerValid;
    } else {
      isCompleteBasics = firstNameController.text.isNotEmpty &&
          lastNameController.text.isNotEmpty;
    }
    emit(ChangeStatusSteps());
    emit(ValidateBasics());
    return isCompleteBasics!;
  }

  void _clearHighlightsRolePermission(List<PermissionOption> nodes) {
    for (var node in nodes) {
      node.isHighlighted = false;
      if (node.subOptions.isNotEmpty) {
        _clearHighlightsRolePermission(node.subOptions);
      }
    }
  }

  EditUserModel? res = EditUserModel(
      spaces: [],
      jobTitle: '',
      phoneNumber: '',
      uuid: '',
      email: '',
      firstName: '',
      lastName: '',
      roleType: '',
      status: '',
      invitedBy: '',
      createdDate: '',
      createdTime: '');

  Future<void> getUserById(
    GetUserByIdEvent event,
    Emitter<UsersState> emit,
  ) async {
    emit(UsersLoadingState());

    try {
      var spaceBloc =
          NavigationService.navigatorKey.currentContext!.read<SpaceTreeBloc>();
      final projectUuid = await ProjectManager.getProjectUUID() ?? '';

      if (event.uuid?.isNotEmpty ?? false) {
        final res =
            await UserPermissionApi().fetchUserById(event.uuid, projectUuid);

        if (res != null) {
          // Populate the text controllers
          firstNameController.text = res.firstName;
          lastNameController.text = res.lastName;
          emailController.text = res.email;
          phoneController.text = res.phoneNumber ?? '';
          jobTitleController.text = res.jobTitle ?? '';
          res.roleType;
          res.spaces.map((space) {
            selectedIds.add(space.uuid);
            CommunityModel community = spaceBloc.state.communityList
                .firstWhere((item) => item.uuid == space.communityUuid);
            spaceBloc.add(OnSpaceSelected(community, space.uuid, []));
          }).toList();

          // if (updatedCommunities.isNotEmpty) {
          //   // Create a list of UUIDs to mark
          //   final uuidsToMark = res.spaces.map((space) => space.uuid).toList();
          //   // Print all IDs and mark nodes in updatedCommunities
          //   debugPrint('Printing and marking nodes in updatedCommunities:');
          //   _printAndMarkNodes(updatedCommunities, uuidsToMark);
          // }
          final roleId = roles
              .firstWhere((element) =>
                  element.type ==
                  res.roleType.toString().toLowerCase().replaceAll("_", " "))
              .uuid;
          debugPrint('Role ID: $roleId');
          roleSelected = roleId;
          add(PermissionEvent(roleUuid: roleSelected));
          emit(ChangeStatusSteps());
        } else {}
      } else {}
    } catch (_) {}
  }

  void _printAndMarkNodes(List<TreeNode> nodes, List<String> uuidsToMark,
      [int level = 0]) {
    for (final node in nodes) {
      if (uuidsToMark.contains(node.uuid)) {
        node.isChecked = true;
        debugPrint(
            '${'  ' * level}MATCH FOUND: Node ID: ${node.uuid}, Title: ${node.title} is marked as checked.');
      } else {
        debugPrint(
            '${'  ' * level}Node ID: ${node.uuid}, Title: ${node.title}');
      }
      if (node.children.isNotEmpty) {
        _printAndMarkNodes(node.children, uuidsToMark, level + 1);
      }
    }
  }

  void _onToggleNodeExpansion(
    ToggleNodeExpansion event,
    Emitter<UsersState> emit,
  ) {
    emit(UsersLoadingState());
    event.node.isExpanded = !event.node.isExpanded;
    emit(ChangeStatusSteps());
  }

  void _onToggleNodeCheck(
    ToggleNodeCheck event,
    Emitter<UsersState> emit,
  ) {
    emit(UsersLoadingState());
    //Toggle node's checked state
    event.node.isChecked = !event.node.isChecked;
    debugPrint(
      'Node toggled. ID: ${event.node.uuid}, isChecked: ${event.node.isChecked}',
    );
    // Update children and parent
    _updateChildrenCheckStatus(event.node, event.node.isChecked);
    _updateParentCheckStatus(event.node);

    // Finally, emit a new state
    emit(ChangeStatusSteps());
  }

  void _updateChildrenCheckStatus(TreeNode node, bool isChecked) {
    for (var child in node.children) {
      child.isChecked = isChecked;
      _updateChildrenCheckStatus(child, isChecked);
    }
  }

  void _updateParentCheckStatus(TreeNode node) {
    TreeNode? parent = _findParent(updatedCommunities, node);
    if (parent != null) {
      parent.isChecked = _areAllChildrenChecked(parent);
      _updateParentCheckStatus(parent);
    }
  }

  bool _areAllChildrenChecked(TreeNode node) {
    return node.children.isNotEmpty &&
        node.children.every((child) =>
            child.isChecked &&
            (child.children.isEmpty || _areAllChildrenChecked(child)));
  }

  TreeNode? _findParent(List<TreeNode> nodes, TreeNode target) {
    for (var node in nodes) {
      if (node.children.contains(target)) {
        return node;
      }
      final parent = _findParent(node.children, target);
      if (parent != null) {
        return parent;
      }
    }
    return null;
  }

  @override
  Future<void> close() {
    emailController.dispose();
    firstNameController.dispose();
    lastNameController.dispose();
    emailController.dispose();
    phoneController.dispose();
    jobTitleController.dispose();
    roleSearchController.dispose();
    return super.close();
  }
}
