import 'dart:async';

import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:starting_template/domain/usecases/counter/decrement.dart';
import 'package:starting_template/domain/usecases/counter/get_current.dart';
import 'package:starting_template/domain/usecases/counter/increment.dart';
import 'package:starting_template/domain/usecases/counter/reset.dart';

part 'counter_state.dart';

/// {@template counter_cubit}
/// CounterCubit manages UI depending on counter state.
/// {@endtemplate}
class CounterCubit extends Cubit<CounterState> {
  /// {@macro counter_cubit}
  CounterCubit({
    required Decrement decrement,
    required Increment increment,
    required GetCurrent getCurrent,
    required Reset reset,
  })  : _decrement = decrement,
        _increment = increment,
        _getCurrent = getCurrent,
        _reset = reset,
        super(const CounterState(0));

  final Decrement _decrement;
  final Increment _increment;
  final GetCurrent _getCurrent;
  final Reset _reset;

  /// Decrement counter.
  FutureOr<void> decrement([int by = 1]) async {
    final result = await _decrement.call(by);

    result.fold(
      (integer) => emit(CounterState(integer.value)),
      addError,
    );

    return;
  }

  /// Increment counter.
  FutureOr<void> increment([int by = 1]) async {
    final result = await _increment.call(by);

    result.fold(
      (integer) => emit(CounterState(integer.value)),
      addError,
    );

    return;
  }

  /// Get current counter state.
  FutureOr<void> getCurrent() async {
    final result = await _getCurrent.call(null);

    result.fold(
      (integer) => emit(CounterState(integer.value)),
      addError,
    );

    return;
  }

  /// Reset counter state.
  FutureOr<void> reset() async {
    final result = await _reset.call(null);

    result.fold(
      (integer) => emit(CounterState(integer.value)),
      addError,
    );

    return;
  }

  @override
  void onError(Object error, StackTrace stackTrace) {
    emit(state);
    super.onError(error, stackTrace);
  }
}
