import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:flutter/foundation.dart';
import 'package:krow/core/application/clients/api/api_exception.dart';
import 'package:krow/core/application/di/injectable.dart';
import 'package:krow/core/data/models/staff/pivot.dart';
import 'package:krow/core/entity/staff_contact_entity.dart';
import 'package:krow/features/clock_manual/domain/clock_manual_repository.dart';

part 'clock_manual_event.dart';
part 'clock_manual_state.dart';

class ClockManualBloc extends Bloc<ClockManualEvent, ClockManualState> {
  var staffContacts = <StaffContact>[];

  ClockManualBloc({required this.staffContacts})
      : super(ClockManualState(
          timers: Map.fromEntries(
              staffContacts.map((e) => MapEntry(e.id, ValueNotifier<int>(0)))),
          ongoingStaffContacts: staffContacts
              .where((element) => element.status == PivotStatus.ongoing)
              .toList()
            ..sort((a, b) => a.startAt.compareTo(b.startAt)),
          confirmedStaffContacts: staffContacts
              .where((element) => element.status == PivotStatus.confirmed)
              .toList()
            ..sort((a, b) => a.startAt.compareTo(b.startAt)),
        )) {
    on<ChangeSelectedTabIndexClockManual>(_onChangeSelectedTabIndexStaffManual);
    on<ClockInManual>(_onClockInStaffManual);
    on<SortStaffContactsClockManual>(_sortStaffContactsClockManual);
    on<ClockOutManual>(_onClockOutStaff);
    on<CancelClockInManual>(_onCancelClockInStaffManual);
  }

  void _onChangeSelectedTabIndexStaffManual(
      ChangeSelectedTabIndexClockManual event, Emitter<ClockManualState> emit) {
    emit(state.copyWith(selectedTabIndex: event.index));
  }

  void _onClockInStaffManual(ClockInManual event, emit) async {
    emit(state.copyWith(inLoading: true));
    try {
      await getIt<ClockManualRepository>()
          .trackClientClockin(event.staffContact.id);

      _startCountdownTimer(
          state.timers[event.staffContact.id]!, event.staffContact);
    } catch (e) {
      if (e is DisplayableException) {
        emit(state.copyWith(
          errorMessage: e.message,
        ));
      }
    }
    emit(state.copyWith(inLoading: false));
  }

  void _onClockOutStaff(ClockOutManual event, emit) async {
    emit(state.copyWith(inLoading: false));
    try {
      await getIt<ClockManualRepository>()
          .trackClientClockout(event.staffContact.id);
      event.staffContact.status = PivotStatus.completed;
      add(SortStaffContactsClockManual());
    } catch (e) {
      if (e is DisplayableException) {
        emit(state.copyWith(
          errorMessage: e.message,
        ));
      }
    }
    emit(state.copyWith(inLoading: false));
  }

  void _onCancelClockInStaffManual(CancelClockInManual event, emit) async {
    emit(state.copyWith(inLoading: true));
    try {
      await getIt<ClockManualRepository>().cancelClockin(event.staffContact.id);
      state.timers[event.staffContact.id]!.value = -1;
      event.staffContact.status = PivotStatus.confirmed;
      add(SortStaffContactsClockManual());
    } catch (e) {
      if (e is DisplayableException) {
        emit(state.copyWith(
          errorMessage: e.message,
        ));
      }
    }
    emit(state.copyWith(inLoading: false));
  }

  void _sortStaffContactsClockManual(SortStaffContactsClockManual event, emit) {
    emit(state.copyWith(
      ongoingStaffContacts: staffContacts
          .where((element) => element.status == PivotStatus.ongoing)
          .toList()
        ..sort((a, b) => a.startAt.compareTo(b.startAt)),
      confirmedStaffContacts: staffContacts
          .where((element) => element.status == PivotStatus.confirmed)
          .toList()
        ..sort((a, b) => a.startAt.compareTo(b.startAt)),
    ));
  }

  void _startCountdownTimer(ValueNotifier<int> cancelTimer, staffContact) {
    cancelTimer.value = 5;
    Timer.periodic(const Duration(seconds: 1), (timer) {
      if (cancelTimer.value > 0) {
        cancelTimer.value -= 1;
      } else if (cancelTimer.value == 0) {
        staffContact.status = PivotStatus.ongoing;
        add(SortStaffContactsClockManual());
        timer.cancel();
      } else {
        timer.cancel();
      }
    });
  }
}
