import 'dart:async';
import 'package:be_happy/core/failures.dart';
import 'package:be_happy/domain/entities/scooter_order.dart';
import 'package:be_happy/domain/usecase/get_profile_usecase.dart';
import 'package:collection/collection.dart';

import 'package:be_happy/domain/entities/payment_card.dart';
import 'package:be_happy/domain/usecase/book_scooter_usecase.dart';
import 'package:be_happy/domain/usecase/get_payment_cards_usecase.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import '../../core/result.dart';
import '../../domain/entities/tariff.dart';
import '../../domain/usecase/get_available_tariffs_usecase.dart';
import '../event/tariff_sheet_event.dart';
import '../state/tariff_sheet_state.dart';

class TariffSheetBloc extends Bloc<TariffSheetEvent, TariffSheetState> {
  final GetAvailableTariffsUsecase _getAvailableTariffsUsecase;
  final GetProfileUseCase _getProfileUseCase;
  final GetPaymentCardsUsecase _getPaymentCardsUsecase;
  final BookScooterUsecase _bookScooterUsecase;

  TariffSheetBloc(
    this._getAvailableTariffsUsecase,
    this._getProfileUseCase,
    this._getPaymentCardsUsecase,
    this._bookScooterUsecase,
  ) : super(TariffSheetState(status: TariffSheetStatus.initial)) {
    on<TariffSheetStarted>(_onStarted);
    on<PaymentCardChanged>(_onPaymentCardChanged);
    on<BookScooterPressed>(_onBookScooterPressed);
    on<SelectBalancePressed>(_onSelectBalancePressed);
    on<InsuranceToggled>(_onInsuranceToggled);
  }

  Future<void> _onStarted(
    TariffSheetStarted event,
    Emitter<TariffSheetState> emit,
  ) async {
    emit(state.copyWith(status: TariffSheetStatus.loading));

    try {
      final result = await _getAvailableTariffsUsecase(event.scooterId);
      final cards_result = await _getPaymentCardsUsecase();

      if (result is Success<List<Tariff>> &&
          cards_result is Success<List<PaymentCard>>) {
        emit(
          state.copyWith(
            status: TariffSheetStatus.success,
            tariffs: result.data ?? [],
            selectedCard: cards_result.data?.firstWhereOrNull(
              (element) => element.isMain,
            ),
          ),
        );
      } else {
        emit(
          state.copyWith(
            status: TariffSheetStatus.failure,
            errorMessage: 'Failed to load tariffs',
          ),
        );
      }
    } catch (e, stackTrace) {
      emit(
        state.copyWith(
          status: TariffSheetStatus.failure,
          errorMessage: "ERROR: ${e.toString()} \n $stackTrace",
        ),
      );
    }
  }

  FutureOr<void> _onPaymentCardChanged(
    PaymentCardChanged event,
    Emitter<TariffSheetState> emit,
  ) {
    try {
      emit(
        state.copyWith(
          status: TariffSheetStatus.success,
          selectedCard: event.card,
          useBalance: false,
        ),
      );
    } catch (e) {
      emit(
        state.copyWith(
          status: TariffSheetStatus.failure,
          errorMessage: 'Failed to change card',
        ),
      );
    }
  }

  FutureOr<void> _onBookScooterPressed (
    BookScooterPressed event,
    Emitter<TariffSheetState> emit,
  ) async {
    try {
      final result = await _bookScooterUsecase(
        scooterId: event.scooterId,
        planId: event.planId,
        cardId: event.cardId,
        subscriptionId: event.subscriptionId,
        isBalance: event.isBalance,
        isInsurance: event.isInsurance,
      );

      switch (result) {

        case Success<ScooterOrder>():
          // TODO: Handle this case.
          throw UnimplementedError();
        case Failure<ScooterOrder>():
          if (result is WrongZoneFailure) {
            emit(
              state.copyWith(
                status: TariffSheetStatus.failure,
                errorMessage: result.failure.message,
              ),
            );
          }
      }

    } catch (e) {
      emit(
        state.copyWith(
          status: TariffSheetStatus.failure,
          errorMessage: 'Failed to book scooter',
        ),
      );
    }
  }

  FutureOr<void> _onSelectBalancePressed(SelectBalancePressed event, Emitter<TariffSheetState> emit) async {
    final profile = await _getProfileUseCase();

    emit(state.copyWith(
      useBalance: true,
      userBalance: profile.balance,
      selectedCard: null,
    ));
  }

  FutureOr<void> _onInsuranceToggled(InsuranceToggled event, Emitter<TariffSheetState> emit) async {
    emit(state.copyWith(isInsurance: event.isEnabled));
  }
}
