import 'dart:async';

import 'package:injectable/injectable.dart';
import 'package:intl/intl.dart';
import 'package:krow/features/shifts/data/models/staff_shift.dart';
import 'package:krow/features/shifts/data/shifts_api_provider.dart';
import 'package:krow/features/shifts/domain/shift_entity.dart';
import 'package:krow/features/shifts/domain/shifts_repository.dart';
import 'package:krow/features/shifts/presentation/dialogs/complete_dialog/shift_complete_dialog.dart';

@Singleton(as: ShiftsRepository)
class ShiftsRepositoryImpl extends ShiftsRepository {
  final ShiftsApiProvider _apiProvider;
  StreamController<EventShiftRoleStaffStatus>? _statusController;

  ShiftsRepositoryImpl({required ShiftsApiProvider apiProvider})
      : _apiProvider = apiProvider;

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

  @override
  Future<List<ShiftEntity>> getShifts(
      {String? lastItemId, required ShiftStatusFilterType statusFilter}) async {
    var paginationWrapper = await _apiProvider
        .fetchShifts(statusFilterToGqlString(statusFilter), after: lastItemId);
    return paginationWrapper.edges.map((e) {
      return ShiftEntity.fromStaffShift(
        e.node,
        cursor: (paginationWrapper.pageInfo?.hasNextPage??false) ? e.cursor : null,
      );
    }).toList();
  }

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

  @override
  Future<void> confirmShift(ShiftEntity shiftViewModel) async {
    var result = await _apiProvider.confirmShift(shiftViewModel.id);
    _statusController?.add(EventShiftRoleStaffStatus.assigned);
    _statusController?.add(EventShiftRoleStaffStatus.confirmed);
    return result;
  }

  @override
  Future<void> clockInShift(ShiftEntity shiftViewModel) async {
    // try {
    await _apiProvider.clockInShift(shiftViewModel.id);
    _statusController?.add(EventShiftRoleStaffStatus.assigned);
    _statusController?.add(EventShiftRoleStaffStatus.ongoing);
    // } catch (e) {
    //   _statusController?.add(EventShiftRoleStaffStatus.assigned);
    //   _statusController?.add(EventShiftRoleStaffStatus.ongoing);
    //   rethrow;
    // }
  }

  @override
  Future<void> completeShift(
      ShiftEntity shiftViewModel, ClockOutDetails clockOutDetails, bool isPast) async {
    if (clockOutDetails.reason != null) {
      _apiProvider.completeShiftNoBreak(
        shiftViewModel.id,
        reason: clockOutDetails.reason,
        additionalReason: clockOutDetails.additionalReason,
      );
    } else {
      var breakInTime =
          DateFormat('H:mm').parse(clockOutDetails.breakStartTime!);
      var start = DateTime(
          shiftViewModel.startDate.year,
          shiftViewModel.startDate.month,
          shiftViewModel.startDate.day,
          breakInTime.hour,
          breakInTime.minute);
      var breakOutTime =
          DateFormat('H:mm').parse(clockOutDetails.breakEndTime!);
      var end = DateTime(
          shiftViewModel.startDate.year,
          shiftViewModel.startDate.month,
          shiftViewModel.startDate.day,
          breakOutTime.hour,
          breakOutTime.minute);
      _apiProvider.completeShift(
        shiftViewModel.id,
        isPast: isPast,
        breakIn: DateFormat('yyyy-MM-dd HH:mm:ss').format(start),
        breakOut: DateFormat('yyyy-MM-dd HH:mm:ss').format(end),
      );
    }
    _statusController?.add(EventShiftRoleStaffStatus.ongoing);
    _statusController?.add(EventShiftRoleStaffStatus.completed);
  }

  @override
  Future<void> forceClockOut(String id) async {
    await _apiProvider.completeShift(id);
    _statusController?.add(EventShiftRoleStaffStatus.assigned);
    _statusController?.add(EventShiftRoleStaffStatus.confirmed);
  }

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

  @override
  declineShift(
      ShiftEntity shiftViewModel, String? reason, String? additionalReason) {
    _apiProvider.declineShift(
      shiftViewModel.id,
      reason: reason,
      additionalReason: additionalReason,
    );
    _statusController?.add(EventShiftRoleStaffStatus.assigned);
    _statusController?.add(EventShiftRoleStaffStatus.canceledByStaff);
  }

  @override
  cancelShift(
      ShiftEntity shiftViewModel, String? reason, String? additionalReason) {
    _apiProvider.cancelShift(
      shiftViewModel.id,
      reason: reason,
      additionalReason: additionalReason,
    );
    _statusController?.add(EventShiftRoleStaffStatus.assigned);
    _statusController?.add(EventShiftRoleStaffStatus.canceledByStaff);
  }

  @override
  Future<ShiftEntity?> getShiftById(String id) async {
    return ShiftEntity.fromStaffShift(
        cursor: '', await _apiProvider.getShiftById(id));
  }

  @override
  Future<List<ShiftEntity>> getMissBreakFinishedShift() async{
    var paginationWrapper = await _apiProvider
        .getMissBreakFinishedShift();
    return paginationWrapper.edges.map((e) {
      return ShiftEntity.fromStaffShift(
        e.node,
        cursor: (paginationWrapper.pageInfo?.hasNextPage??false) ? e.cursor : null,
      );
    }).toList();
  }
}
