import 'package:dartz/dartz.dart' hide Order;
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart' hide Order;

import '../../../domain/order/order.dart';

part 'order_loader_event.dart';
part 'order_loader_state.dart';
part 'order_loader_bloc.freezed.dart';

@injectable
class OrderLoaderBloc extends Bloc<OrderLoaderEvent, OrderLoaderState> {
  final IOrderRepository _repository;
  OrderLoaderBloc(this._repository) : super(OrderLoaderState.initial()) {
    on<OrderLoaderEvent>(_onOrderLoaderEvent);
  }

  Future<void> _onOrderLoaderEvent(
    OrderLoaderEvent event,
    Emitter<OrderLoaderState> emit,
  ) {
    return event.map(
      rangeDateChanged: (e) async {
        emit(state.copyWith(dateFrom: e.dateFrom, dateTo: e.dateTo));
      },
      statusChanged: (e) async {
        emit(state.copyWith(status: e.status));
      },
      searchChanged: (e) async {
        emit(state.copyWith(search: e.search));
      },
      outletChanged: (e) async {
        emit(state.copyWith(outletId: e.outletId));
      },
      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<OrderLoaderState> _mapFetchedToState(
    OrderLoaderState state, {
    bool isRefresh = false,
  }) async {
    state = state.copyWith(isFetching: false);

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

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

    final failureOrOrder = await _repository.get(
      status: state.status == 'all' ? null : state.status,
      page: state.page,
      search: state.search,
      outletId: state.outletId,
      dateFrom: state.dateFrom,
      dateTo: state.dateTo,
    );

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

    return state;
  }
}
