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

import '../../../domain/outlet/outlet.dart';

part 'outlet_loader_event.dart';
part 'outlet_loader_state.dart';
part 'outlet_loader_bloc.freezed.dart';

@injectable
class OutletLoaderBloc extends Bloc<OutletLoaderEvent, OutletLoaderState> {
  final IOutletRepository _outletRepository;

  OutletLoaderBloc(this._outletRepository)
    : super(OutletLoaderState.initial()) {
    on<OutletLoaderEvent>(_onOutletLoaderEvent);
  }

  Future<void> _onOutletLoaderEvent(
    OutletLoaderEvent event,
    Emitter<OutletLoaderState> emit,
  ) {
    return event.map(
      fetched: (e) async {
        var newState = state;

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

          emit(newState);
        }

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

        emit(newState);
      },
    );
  }

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

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

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

    final failureOrOutlet = await _outletRepository.getOutlets(
      page: state.page,
    );

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

    return state;
  }
}
