import 'dart:async';

import 'package:boilerplate/core/utils/shared_preferences_util.dart';
import 'package:boilerplate/data/models/product/get_product_list_req_model.dart';
import 'package:boilerplate/domain/entities/product/product_data.dart';
import 'package:boilerplate/domain/usecases/product/add_product_cart_use_case.dart';
import 'package:boilerplate/domain/usecases/product/add_product_favorite_use_case.dart';
import 'package:boilerplate/domain/usecases/product/check_product_cart_use_case.dart';
import 'package:boilerplate/domain/usecases/product/check_product_favorite_use_case.dart';
import 'package:boilerplate/domain/usecases/product/get_product_detail_use_case.dart';
import 'package:boilerplate/domain/usecases/product/get_product_list_use_case.dart';
import 'package:boilerplate/domain/usecases/product/remove_product_cart_use_case.dart';
import 'package:boilerplate/domain/usecases/product/remove_product_favorite_use_case.dart';
import 'package:dartz/dartz.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:injectable/injectable.dart';

import '../../../data/models/app/failure.dart';

part 'product_detail_event.dart';
part 'product_detail_state.dart';

@injectable
class ProductDetailBloc extends Bloc<ProductDetailEvent, ProductDetailState> {
  final GetProductDetailUseCase _getProductDetailUseCase;
  final GetProductListUseCase _getProductListUseCase;
  final AddProductFavoriteUseCase _addProductFavoriteUseCase;
  final RemoveProductFavoriteUseCase _removeProductFavoriteUseCase;
  final CheckProductFavoriteUseCase _checkProductFavoriteUseCase;
  final AddProductCartUseCase _addProductCartUseCase;
  final RemoveProductCartUseCase _removeProductCartUseCase;
  final CheckProductCartUseCase _checkProductCartUseCase;

  @factoryParam
  final SharedPreferencesUtil _pref;

  ProductDetailBloc(
    this._getProductDetailUseCase,
    this._getProductListUseCase,
    this._addProductFavoriteUseCase,
    this._removeProductFavoriteUseCase,
    this._pref,
    this._checkProductFavoriteUseCase,
    this._addProductCartUseCase,
    this._removeProductCartUseCase,
    this._checkProductCartUseCase,
  ) : super(InitialState(ProductDetailStateData())) {
    on<GetProductDetailEvent>(_onGetProductDetail);
    on<GetInterestProductsMoreEvent>(_onGetInterestProductsMore);
    on<ChangeProductFavoriteEvent>(_onChangeProductFavorite);
    on<ChangeProductCartEvent>(_onChangeProductCart);
  }

  Future<FutureOr<void>> _onGetProductDetail(
    GetProductDetailEvent event,
    Emitter<ProductDetailState> emit,
  ) async {
    final result = await _getProductDetailUseCase.execute(event.productId);
    final isFav = await _checkProductFavoriteUseCase.execute(event.productId);
    final isInCart = await _checkProductCartUseCase.execute(event.productId);

    result.fold((data) {
      emit(GetProductDetailSuccessState(state.data.copyWith(
          newProductData: data,
          newUserId: _pref.getInt(SharedPreferencesUtil.keyUserId),
          newFavorite: isFav.fold((status) => status, (fail) => false),
          newIsInCart: isInCart.fold((status) => status, (fail) => false))));
    }, (fail) {
      emit(GetProductDetailFailState(state.data));
    });
  }

  Future<FutureOr<void>> _onGetInterestProductsMore(
    GetInterestProductsMoreEvent event,
    Emitter<ProductDetailState> emit,
  ) async {
    final result =
        await _getProductListUseCase.execute(GetProductListReqModel());

    result.fold((data) {
      emit(GetInterestProductsSuccessState(state.data.copyWith(
        newInterestProducts: data,
      )));
    }, (fail) {
      emit(GetInterestProductsSuccessState(state.data));
    });
  }

  Future<FutureOr<void>> _onChangeProductFavorite(
    ChangeProductFavoriteEvent event,
    Emitter<ProductDetailState> emit,
  ) async {
    if (state.data.productData != null) {
      Either<bool, Failure> result;

      if (event.isFav) {
        result = await _removeProductFavoriteUseCase.execute(
          state.data.productData!.id!,
        );
      } else {
        result = await _addProductFavoriteUseCase.execute(
          state.data.productData!.id!,
        );
      }

      result.fold((status) {
        emit(SetFavoriteSuccessState(state.data.copyWith(
          newFavorite: event.isFav ? !status : status,
        )));
      }, (fail) {
        emit(SetFavoriteFailState(state.data));
      });
    }
  }

  Future<FutureOr<void>> _onChangeProductCart(
    ChangeProductCartEvent event,
    Emitter<ProductDetailState> emit,
  ) async {
    if (state.data.productData != null) {
      Either<bool, Failure> result;

      if (event.isInCart) {
        result = await _removeProductCartUseCase.execute(
          state.data.productData!.id!,
          state.data.productData!.store!.id,
        );
      } else {
        result = await _addProductCartUseCase.execute(
          state.data.productData!.id!,
          state.data.productData!.store!.id,
        );
      }

      result.fold((status) {
        emit(SetProductCartSuccessState(state.data.copyWith(
          newFavorite: event.isInCart ? !status : status,
        )));
      }, (fail) {
        emit(SetProductCartFailState(state.data));
      });
    }
  }
}
