import 'package:bloc/bloc.dart';
import 'package:collection/collection.dart';
import 'package:dartz/dartz.dart' hide Order;
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart' hide Order;
import 'package:uuid/uuid.dart';

import '../../../common/types/void_type.dart';
import '../../../domain/order/order.dart';

part 'void_form_event.dart';
part 'void_form_state.dart';
part 'void_form_bloc.freezed.dart';

@injectable
class VoidFormBloc extends Bloc<VoidFormEvent, VoidFormState> {
  final IOrderRepository _repository;
  VoidFormBloc(this._repository) : super(VoidFormState.initial()) {
    on<VoidFormEvent>(_onVoidFormEvent);
  }

  Future<void> _onVoidFormEvent(
    VoidFormEvent event,
    Emitter<VoidFormState> emit,
  ) {
    return event.map(
      setOrder: (e) async {
        List<OrderItem> pendingItems = e.order.orderItems
            .where((item) => item.status == 'pending')
            .toList();

        emit(state.copyWith(order: e.order, pendingItems: pendingItems));
      },
      voidTypeChanged: (e) async {
        emit(state.copyWith(voidType: e.voidType));
      },
      voidReasonChanged: (e) async {
        emit(state.copyWith(voidReason: e.voidReason));
      },
      itemQuantityChanged: (e) async {
        final newQuantities = Map<String, int>.from(
          state.selectedItemQuantities,
        );

        if (e.quantity > 0) {
          newQuantities[e.itemId] = e.quantity;
        } else {
          newQuantities.remove(e.itemId);
        }

        // Recalculate total price
        int newTotal = 0;
        for (var entry in newQuantities.entries) {
          final item = state.pendingItems.firstWhereOrNull(
            (item) => item.id == entry.key,
          );
          if (item == null) continue;
          newTotal += item.unitPrice.toInt() * entry.value;
        }

        emit(
          state.copyWith(
            selectedItemQuantities: newQuantities,
            totalPriceVoid: newTotal,
          ),
        );
      },
      clearSelectedItem: (e) async {
        emit(state.copyWith(selectedItemQuantities: {}, totalPriceVoid: 0));
      },
      submitted: (e) async {
        Either<OrderFailure, Unit> failureOrVoid;
        List<OrderItem> voidItems = [];

        if (state.voidType.isItem) {
          state.selectedItemQuantities.forEach((itemId, voidQty) {
            final originalItem = state.order.orderItems.firstWhereOrNull(
              (item) => item.id == itemId,
            );

            if (originalItem == null) return;

            voidItems.add(
              OrderItem(
                id: originalItem.id,
                orderId: originalItem.orderId,
                productId: originalItem.productId,
                productName: originalItem.productName,
                categoryId: originalItem.categoryId,
                categoryName: originalItem.status,
                productVariantId: originalItem.productVariantId,
                productVariantName: originalItem.productVariantName,
                quantity: voidQty,
                unitPrice: originalItem.unitPrice,
                totalPrice: (originalItem.unitPrice) * voidQty,
                modifiers: originalItem.modifiers,
                notes: originalItem.notes,
                status: originalItem.status,
                createdAt: originalItem.createdAt,
                updatedAt: originalItem.updatedAt,
                printerType: originalItem.printerType,
                paidQuantity: originalItem.paidQuantity,
                printToChecker: originalItem.printToChecker,
              ),
            );
          });
        }

        // Generate new idempotency key saat user intent (tap Void)
        // Kalau sedang retry, pakai key yang sama
        final idempotencyKey = state.idempotencyKey ?? const Uuid().v4();

        emit(state.copyWith(
          isSubmitting: true,
          failureOrVoid: none(),
          idempotencyKey: idempotencyKey,
        ));

        failureOrVoid = await _repository.voidOrder(
          orderId: state.order.id,
          reason: state.voidReason ?? '',
          orderItems: voidItems,
          type: state.voidType.toStringType(),
          idempotencyKey: idempotencyKey,
        );

        emit(
          state.copyWith(
            isSubmitting: false,
            failureOrVoid: optionOf(failureOrVoid),
            voidItems: state.voidType.isItem ? voidItems : state.pendingItems,
            // Clear key on success, keep on failure for retry
            idempotencyKey: failureOrVoid.isRight() ? null : idempotencyKey,
          ),
        );
      },
      clearState: (e) async {
        emit(VoidFormState.initial());
      },
    );
  }
}
