import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/spaces_management/all_spaces/model/tag.dart';
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_event.dart';
import 'package:syncrow_web/pages/spaces_management/assign_tag_models/bloc/assign_tag_model_state.dart';

class AssignTagModelBloc extends Bloc<AssignTagModelEvent, AssignTagModelState> {
  final List<Tag> projectTags;

  AssignTagModelBloc(this.projectTags) : super(AssignTagModelInitial()) {
    on<InitializeTagModels>((event, emit) {
      final initialTags = event.initialTags;

      final existingTagCounts = <String, int>{};
      for (var tag in initialTags) {
        if (tag.product != null) {
          existingTagCounts[tag.product!.uuid] = (existingTagCounts[tag.product!.uuid] ?? 0) + 1;
        }
      }

      final tags = <Tag>[];

      for (var selectedProduct in event.addedProducts) {
        final existingCount = existingTagCounts[selectedProduct.productId] ?? 0;

        if (selectedProduct.count == 0 || selectedProduct.count <= existingCount) {
          tags.addAll(initialTags.where((tag) => tag.product?.uuid == selectedProduct.productId));
          continue;
        }

        final missingCount = selectedProduct.count - existingCount;

        tags.addAll(initialTags.where((tag) => tag.product?.uuid == selectedProduct.productId));

        if (missingCount > 0) {
          tags.addAll(List.generate(
            missingCount,
            (index) => Tag(
              tag: '',
              product: selectedProduct.product,
              location: 'Main Space',
            ),
          ));
        }
      }

      final updatedTags = _calculateAvailableTags(projectTags, tags);

      emit(AssignTagModelLoaded(
          tags: tags,
          updatedTags: updatedTags,
          isSaveEnabled: _validateTags(tags),
          errorMessage: ''));
    });

    on<UpdateTag>((event, emit) {
      final currentState = state;
      if (currentState is AssignTagModelLoaded && currentState.tags.isNotEmpty) {
        final tags = List<Tag>.from(currentState.tags);

        if (event.index < 0 || event.index >= tags.length) return;

        tags[event.index] = tags[event.index].copyWith(
          tag: event.tag.tag,
          uuid: event.tag.uuid,
          product: event.tag.product,
          internalId: event.tag.internalId,
          location: event.tag.location,
        );

        final updatedTags = _calculateAvailableTags(projectTags, tags);

        emit(AssignTagModelLoaded(
          tags: tags,
          updatedTags: updatedTags,
          isSaveEnabled: _validateTags(tags),
          errorMessage: _getValidationError(tags),
        ));
      }
    });

    on<UpdateLocation>((event, emit) {
      final currentState = state;

      if (currentState is AssignTagModelLoaded && currentState.tags.isNotEmpty) {
        final tags = List<Tag>.from(currentState.tags);
        // Use copyWith for immutability
        tags[event.index] = tags[event.index].copyWith(location: event.location);

        final updatedTags = _calculateAvailableTags(projectTags, tags);

        emit(AssignTagModelLoaded(
          tags: tags,
          updatedTags: updatedTags,
          isSaveEnabled: _validateTags(tags),
          errorMessage: _getValidationError(tags),
        ));
      }
    });

    on<ValidateTagModels>((event, emit) {
      final currentState = state;

      if (currentState is AssignTagModelLoaded && currentState.tags.isNotEmpty) {
        final tags = List<Tag>.from(currentState.tags);

        emit(AssignTagModelLoaded(
          tags: tags,
          updatedTags: _calculateAvailableTags(projectTags, tags),
          isSaveEnabled: _validateTags(tags),
          errorMessage: _getValidationError(tags),
        ));
      }
    });

    on<DeleteTagModel>((event, emit) {
      final currentState = state;

      if (currentState is AssignTagModelLoaded && currentState.tags.isNotEmpty) {
        final tags = List<Tag>.from(currentState.tags)..remove(event.tagToDelete);

        final updatedTags = _calculateAvailableTags(projectTags, tags);

        emit(AssignTagModelLoaded(
          tags: tags,
          updatedTags: updatedTags,
          isSaveEnabled: _validateTags(tags),
          errorMessage: _getValidationError(tags),
        ));
      }
    });
  }

  bool _validateTags(List<Tag> tags) {
    final uniqueTags = tags.map((tag) => tag.tag?.trim() ?? '').toSet();
    final hasEmptyTag = tags.any((tag) => (tag.tag?.trim() ?? '').isEmpty);
    final isValid = uniqueTags.length == tags.length && !hasEmptyTag;
    return isValid;
  }

  String? _getValidationError(List<Tag> tags) {
    // Check for duplicate tags

    final nonEmptyTags =
        tags.map((tag) => tag.tag?.trim() ?? '').where((tag) => tag.isNotEmpty).toList();

    final duplicateTags = nonEmptyTags
        .fold<Map<String, int>>({}, (map, tag) {
          map[tag] = (map[tag] ?? 0) + 1;
          return map;
        })
        .entries
        .where((entry) => entry.value > 1)
        .map((entry) => entry.key)
        .toList();

    if (duplicateTags.isNotEmpty) {
      return 'Duplicate tags found: ${duplicateTags.join(', ')}';
    }

    return null;
  }

  List<Tag> _calculateAvailableTags(List<Tag> allTags, List<Tag> selectedTags) {
    final selectedTagSet = selectedTags
        .where((tag) => (tag.tag?.trim().isNotEmpty ?? false))
        .map((tag) => tag.tag!.trim())
        .toSet();

    final availableTags = allTags
        .where((tag) => tag.tag != null && !selectedTagSet.contains(tag.tag!.trim()))
        .toList();

    return availableTags;
  }
}
