mirrored_repositories/AppFlowy/frontend/appflowy_flutter/lib/plugins/database/application/cell
import 'dart:async';

import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database/application/field/field_info.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'text_cell_bloc.freezed.dart';

class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
  TextCellBloc({required this.cellController})
      : super(TextCellState.initial(cellController)) {
    _dispatch();
    _startListening();
  }

  final TextCellController cellController;
  void Function()? _onCellChangedFn;

  @override
  Future<void> close() async {
    if (_onCellChangedFn != null) {
      cellController.removeListener(
        onCellChanged: _onCellChangedFn!,
        onFieldChanged: _onFieldChangedListener,
      );
    }
    await cellController.dispose();
    return super.close();
  }

  void _dispatch() {
    on<TextCellEvent>(
      (event, emit) {
        event.when(
          didReceiveCellUpdate: (String content) {
            emit(state.copyWith(content: content));
          },
          didUpdateField: (fieldInfo) {
            final wrap = fieldInfo.wrapCellContent;
            if (wrap != null) {
              emit(state.copyWith(wrap: wrap));
            }
          },
          didUpdateEmoji: (String emoji) {
            emit(state.copyWith(emoji: emoji));
          },
          updateText: (String text) {
            if (state.content != text) {
              cellController.saveCellData(text, debounce: true);
            }
          },
          enableEdit: (bool enabled) {
            emit(state.copyWith(enableEdit: enabled));
          },
        );
      },
    );
  }

  void _startListening() {
    _onCellChangedFn = cellController.addListener(
      onCellChanged: (cellContent) {
        if (!isClosed) {
          add(TextCellEvent.didReceiveCellUpdate(cellContent ?? ""));
        }
      },
      onFieldChanged: _onFieldChangedListener,
      onRowMetaChanged: cellController.fieldInfo.isPrimary
          ? () {
              if (!isClosed) {
                add(TextCellEvent.didUpdateEmoji(cellController.icon ?? ""));
              }
            }
          : null,
    );
  }

  void _onFieldChangedListener(FieldInfo fieldInfo) {
    if (!isClosed) {
      add(TextCellEvent.didUpdateField(fieldInfo));
    }
  }
}

@freezed
class TextCellEvent with _$TextCellEvent {
  const factory TextCellEvent.didReceiveCellUpdate(String cellContent) =
      _DidReceiveCellUpdate;
  const factory TextCellEvent.didUpdateField(FieldInfo fieldInfo) =
      _DidUpdateField;
  const factory TextCellEvent.updateText(String text) = _UpdateText;
  const factory TextCellEvent.enableEdit(bool enabled) = _EnableEdit;
  const factory TextCellEvent.didUpdateEmoji(String emoji) = _UpdateEmoji;
}

@freezed
class TextCellState with _$TextCellState {
  const factory TextCellState({
    required String content,
    required String emoji,
    required bool enableEdit,
    required bool wrap,
  }) = _TextCellState;

  factory TextCellState.initial(TextCellController cellController) {
    final cellData = cellController.getCellData() ?? "";
    final wrap = cellController.fieldInfo.wrapCellContent ?? false;
    final emoji =
        cellController.fieldInfo.isPrimary ? cellController.icon ?? "" : "";

    return TextCellState(
      content: cellData,
      emoji: emoji,
      enableEdit: false,
      wrap: wrap,
    );
  }
}
