import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:injectable/injectable.dart';
import 'package:krow/core/entity/event_entity.dart';
import 'package:krow/features/events/data/events_api_provider.dart';
import 'package:krow/features/events/domain/events_repository.dart';

@Singleton(as: EventsRepository)
class EventsRepositoryImpl extends EventsRepository {
  final EventsApiProvider _apiProvider;
  StreamController<EventStatus>? _statusController;

  EventsRepositoryImpl({required EventsApiProvider apiProvider})
      : _apiProvider = apiProvider;

  @override
  Stream<EventStatus> get statusStream {
    _statusController ??= StreamController<EventStatus>.broadcast();
    return _statusController!.stream;
  }

  @override
  Future<List<EventEntity>> getEvents(
      {String? lastItemId, required EventStatus statusFilter}) async {
    try {
      var paginationWrapper = await _apiProvider.fetchEvents(
          statusFilterToGqlString(statusFilter),
          after: lastItemId);
      return paginationWrapper?.edges
              .map((e) => EventEntity.fromEventDto(
                    e.node,
                    cursor: paginationWrapper.pageInfo.hasNextPage
                        ? e.cursor
                        : null,
                  ))
              .toList() ??
          [];
    } catch (e) {
      rethrow;
    }
  }

  @override
  void dispose() {
    _statusController?.close();
  }

  statusFilterToGqlString(EventStatus statusFilter) {
    return statusFilter.name;
  }

  @override
  Future<void> cancelClientEvent(String id, EventStatus? status) async {
    try {
      await _apiProvider.cancelClientEvent(id);
      if (!(_statusController?.isClosed ?? true)) {
        if (status != null) _statusController?.add(status);
      }
    } catch (exception) {
      debugPrint(exception.toString());
      rethrow;
    }
  }

  @override
  Future<void> completeClientEvent(String id, {String? comment}) async {
    try {
      await _apiProvider.completeClientEvent(id, comment: comment);
      if (!(_statusController?.isClosed ?? true)) {
        _statusController?.add(EventStatus.finished);
        _statusController?.add(EventStatus.completed);
      }
    } catch (exception) {
      debugPrint(exception.toString());
      rethrow;
    }
  }

  @override
  Future<void> trackClientClockin(String positionStaffId) async {
    try {
      await _apiProvider.trackClientClockin(positionStaffId);
    } catch (exception) {
      debugPrint(exception.toString());
      rethrow;
    }
  }

  @override
  Future<void> trackClientClockout(String positionStaffId) async {
    try {
      await _apiProvider.trackClientClockout(positionStaffId);
    } catch (exception) {
      debugPrint(exception.toString());
      rethrow;
    }
  }

  @override
  Future<void> notShowedPositionStaff(String positionStaffId) async {
    try {
      await _apiProvider.notShowedPositionStaff(positionStaffId);
    } catch (exception) {
      debugPrint(exception.toString());
      rethrow;
    }
  }

  @override
  Future<void> replacePositionStaff(
      String positionStaffId, String reason) async {
    try {
      await _apiProvider.replacePositionStaff(positionStaffId, reason);
    } catch (exception) {
      debugPrint(exception.toString());
      rethrow;
    }
  }

  @override
  void refreshEvents(EventStatus status) {
    if (!(_statusController?.isClosed ?? true)) {
      _statusController?.add(status);
    }
  }

  @override
  Future<EventEntity?> getEventById(String id) async {
    return await _apiProvider.fetchEventById(id).then((event) {
      if (event != null) {
        return EventEntity.fromEventDto(event);
      }
      return null;
    });
  }
}
