import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';

import '../../../domain/payment_method/payment_method.dart';

part 'payment_method_loader_event.dart';
part 'payment_method_loader_state.dart';
part 'payment_method_loader_bloc.freezed.dart';

@injectable
class PaymentMethodLoaderBloc
    extends Bloc<PaymentMethodLoaderEvent, PaymentMethodLoaderState> {
  final IPaymentMethodRepository _repository;
  PaymentMethodLoaderBloc(this._repository)
    : super(PaymentMethodLoaderState.initial()) {
    on<PaymentMethodLoaderEvent>(_onPaymentMethodLoaderEvent);
  }

  Future<void> _onPaymentMethodLoaderEvent(
    PaymentMethodLoaderEvent event,
    Emitter<PaymentMethodLoaderState> emit,
  ) {
    return event.map(
      fetched: (e) async {
        var newState = state;

        if (e.isRefresh) {
          newState = newState.copyWith(isFetching: true);
          emit(newState);
        }

        newState = await _mapFetchedToState(newState, isRefresh: e.isRefresh);
        emit(newState);
      },
    );
  }

  Future<PaymentMethodLoaderState> _mapFetchedToState(
    PaymentMethodLoaderState state, {
    bool isRefresh = false,
  }) async {
    state = state.copyWith(isFetching: false);

    if (state.hasReachedMax && state.paymentMethods.isNotEmpty && !isRefresh) {
      return state;
    }

    if (isRefresh) {
      state = state.copyWith(
        page: 1,
        failureOption: none(),
        hasReachedMax: false,
        paymentMethods: [],
      );
    }

    final failureOrTable = await _repository.getPaymentMethods(
      page: state.page,
    );

    state = failureOrTable.fold(
      (f) {
        if (state.paymentMethods.isNotEmpty) {
          return state.copyWith(hasReachedMax: true);
        }
        return state.copyWith(failureOption: optionOf(f));
      },
      (paymentMethods) {
        return state.copyWith(
          paymentMethods: List.from(state.paymentMethods)
            ..addAll(paymentMethods.paymentMethods),
          failureOption: none(),
          page: state.page + 1,
          hasReachedMax: paymentMethods.paymentMethods.length < 10,
        );
      },
    );

    return state;
  }
}
