import 'dart:async';
import 'dart:typed_data';

import 'package:appflowy/core/notification/search_notification.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-search/notification.pb.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flowy_infra/notifier.dart';

// Do not modify!
const _searchObjectId = "SEARCH_IDENTIFIER";

class SearchListener {
  SearchListener({this.channel});

  /// Use this to filter out search results from other channels.
  ///
  /// If null, it will receive search results from all
  /// channels, otherwise it will only receive search results from the specified
  /// channel.
  ///
  final String? channel;

  PublishNotifier<SearchResultNotificationPB>? _updateNotifier =
      PublishNotifier();
  PublishNotifier<SearchResultNotificationPB>? _updateDidCloseNotifier =
      PublishNotifier();
  SearchNotificationListener? _listener;

  void start({
    void Function(SearchResultNotificationPB)? onResultsChanged,
    void Function(SearchResultNotificationPB)? onResultsClosed,
  }) {
    if (onResultsChanged != null) {
      _updateNotifier?.addPublishListener(onResultsChanged);
    }

    if (onResultsClosed != null) {
      _updateDidCloseNotifier?.addPublishListener(onResultsClosed);
    }

    _listener = SearchNotificationListener(
      objectId: _searchObjectId,
      handler: _handler,
      channel: channel,
    );
  }

  void _handler(
    SearchNotification ty,
    FlowyResult<Uint8List, FlowyError> result,
  ) {
    switch (ty) {
      case SearchNotification.DidUpdateResults:
        result.fold(
          (payload) => _updateNotifier?.value =
              SearchResultNotificationPB.fromBuffer(payload),
          (err) => Log.error(err),
        );
        break;
      default:
        break;
    }
  }

  Future<void> stop() async {
    await _listener?.stop();
    _updateNotifier?.dispose();
    _updateNotifier = null;
    _updateDidCloseNotifier?.dispose();
    _updateDidCloseNotifier = null;
  }
}
