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

part 'customer_loader_event.dart';
part 'customer_loader_state.dart';
part 'customer_loader_bloc.freezed.dart';

@injectable
class CustomerLoaderBloc
    extends Bloc<CustomerLoaderEvent, CustomerLoaderState> {
  final ICustomerRepository _repository;
  CustomerLoaderBloc(this._repository) : super(CustomerLoaderState.initial()) {
    on<CustomerLoaderEvent>(_onCustomerLoaderEvent);
  }

  Future<void> _onCustomerLoaderEvent(
    CustomerLoaderEvent event,
    Emitter<CustomerLoaderState> 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);
      },
      setSelectedCustomer: (e) async {
        emit(state.copyWith(selectedCustomer: e.customer));
      },
    );
  }

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

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

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

    final failureOrCustomer = await _repository.getCustomer(page: state.page);

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

    return state;
  }
}
