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

import '../../../common/types/order_type.dart';
import '../../../domain/customer/customer.dart';
import '../../../domain/order/order.dart';
import '../../../domain/outlet/outlet.dart';
import '../../../domain/payment_method/payment_method.dart';
import '../../../domain/product/product.dart';
import '../../../domain/table/table.dart';
part 'order_form_event.dart';
part 'order_form_state.dart';
part 'order_form_bloc.freezed.dart';

@injectable
class OrderFormBloc extends Bloc<OrderFormEvent, OrderFormState> {
  final IOrderRepository _repository;
  final IOutletRepository _outletRepository;
  OrderFormBloc(this._repository, this._outletRepository)
    : super(OrderFormState.initial()) {
    on<OrderFormEvent>(_onOrderFormBloc);
  }

  Future<void> _onOrderFormBloc(
    OrderFormEvent event,
    Emitter<OrderFormState> emit,
  ) {
    return event.map(
      customerNameChanged: (e) async {
        emit(state.copyWith(customerName: e.customerName));
      },
      paymentMethodChanged: (e) async {
        emit(state.copyWith(paymentMethod: e.payment));
      },
      customerChanged: (e) async {
        emit(state.copyWith(customer: e.customer));
      },
      createOrderWithPayment: (e) async {
        Either<OrderFailure, Order> failureOrOrder;

        emit(
          state.copyWith(
            isCreatingWithPayment: true,
            failureOrCreateOrderWithPayment: none(),
          ),
        );

        final outlet = await _outletRepository.currentOutlet();

        final request = OrderRequest(
          outletId: outlet.id,
          customerId: state.customer?.id ?? '',
          tableNumber: e.table?.tableName ?? '',
          tableId: e.table?.id ?? '',
          orderType: e.orderType.name,
          notes: '',
          customerName: state.customerName ?? "",
          orderItems: e.items
              .map(
                (item) => OrderItemRequest(
                  productId: item.product.id,
                  productVariantId: item.variant?.id ?? "",
                  quantity: item.quantity,
                  unitPrice: item.product.price.toInt(),
                  notes: item.notes,
                ),
              )
              .toList(),
        );

        failureOrOrder = await _repository.createOrderWithPayment(
          request: request,
          paymentMethodId: state.paymentMethod?.id ?? '',
        );

        emit(
          state.copyWith(
            isCreatingWithPayment: false,
            failureOrCreateOrderWithPayment: optionOf(failureOrOrder),
          ),
        );
      },
      createOrder: (e) async {
        Either<OrderFailure, Order> failureOrOrder;

        emit(state.copyWith(isCreating: true, failureOrCreateOrder: none()));

        final outlet = await _outletRepository.currentOutlet();

        final request = OrderRequest(
          outletId: outlet.id,
          customerId: state.customer?.id ?? '',
          tableNumber: e.table?.tableName ?? '',
          tableId: e.table?.id ?? '',
          orderType: e.orderType.name,
          notes: '',
          customerName: state.customerName ?? "",
          orderItems: e.items
              .map(
                (item) => OrderItemRequest(
                  productId: item.product.id,
                  productVariantId: item.variant?.id ?? "",
                  quantity: item.quantity,
                  unitPrice: item.product.price.toInt(),
                  notes: item.notes,
                ),
              )
              .toList(),
        );

        failureOrOrder = await _repository.createOrder(request: request);

        emit(
          state.copyWith(
            isCreating: false,
            failureOrCreateOrder: optionOf(failureOrOrder),
          ),
        );
      },
      addItemOrder: (e) async {
        Either<OrderFailure, Order> failureOrAddItemOrder;

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

        emit(
          state.copyWith(
            isAddingItemOrder: true,
            failureOrAddItemOrder: none(),
            addItemIdempotencyKey: idempotencyKey,
          ),
        );

        final request = e.items
            .map(
              (item) => AddItemOrderRequest(
                productId: item.product.id,
                productVariantId: item.variant?.id ?? '',
                quantity: item.quantity,
                unitPrice: item.product.price.toInt(),
                notes: item.notes,
              ),
            )
            .toList();

        failureOrAddItemOrder = await _repository.addItemOrder(
          id: e.orderId,
          request: request,
          idempotencyKey: idempotencyKey,
        );

        emit(
          state.copyWith(
            isAddingItemOrder: false,
            failureOrAddItemOrder: optionOf(failureOrAddItemOrder),
            // Clear key on success, keep on failure for retry
            addItemIdempotencyKey:
                failureOrAddItemOrder.isRight() ? null : idempotencyKey,
          ),
        );
      },
    );
  }
}
