import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:enaklo_pos/data/datasources/order_remote_datasource.dart';
import 'package:enaklo_pos/data/models/response/order_response_model.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

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

class OrderLoaderBloc extends Bloc<OrderLoaderEvent, OrderLoaderState> {
  final OrderRemoteDatasource _orderRemoteDatasource;

  Timer? _loadMoreDebounce;
  bool _isLoadingMore = false;

  OrderLoaderBloc(this._orderRemoteDatasource)
      : super(OrderLoaderState.initial()) {
    on<_GetByStatus>(_onGetOrderByStatus);
    on<_LoadMore>(_onLoadMore);
    on<_Refresh>(_onRefresh);
    on<_GetById>((event, emit) async {
      emit(const _Loading());
      final result =
          await _orderRemoteDatasource.getOrderById(orderId: event.id);
      result.fold(
        (l) => emit(_Error(l)),
        (r) => emit(_LoadedDetail(r.data!)),
      );
    });
  }

  @override
  Future<void> close() {
    _loadMoreDebounce?.cancel();
    return super.close();
  }

  // Debounce transformer untuk load more
  // EventTransformer<T> _debounceTransformer<T>() {
  //   return (events, mapper) {
  //     return events
  //         .debounceTime(const Duration(milliseconds: 300))
  //         .asyncExpand(mapper);
  //   };
  // }

  // Initial load
  Future<void> _onGetOrderByStatus(
    _GetByStatus event,
    Emitter<OrderLoaderState> emit,
  ) async {
    emit(const _Loading());
    _isLoadingMore = false; // Reset loading state

    final result = await _orderRemoteDatasource.getOrder(
      page: 1,
      limit: event.limit ?? 10,
      status: event.status,
      dateFrom: event.dateFrom,
      dateTo: event.dateTo,
      search: event.search,
    );

    await result.fold(
      (failure) async => emit(_Error(failure)),
      (response) async {
        final orders = response.data?.orders ?? [];
        final hasReachedMax = orders.length < 10;

        emit(_Loaded(
          orders: orders,
          totalOrder: response.data?.totalCount ?? 0,
          hasReachedMax: hasReachedMax,
          currentPage: 1,
          isLoadingMore: false,
        ));
      },
    );
  }

  // Load more with enhanced debouncing
  Future<void> _onLoadMore(
    _LoadMore event,
    Emitter<OrderLoaderState> emit,
  ) async {
    final currentState = state;

    // Enhanced validation
    if (currentState is! _Loaded ||
        currentState.hasReachedMax ||
        _isLoadingMore ||
        currentState.isLoadingMore) {
      return;
    }

    _isLoadingMore = true;

    // Emit loading more state
    emit(currentState.copyWith(isLoadingMore: true));

    final nextPage = currentState.currentPage + 1;

    try {
      final result = await _orderRemoteDatasource.getOrder(
        page: nextPage,
        limit: 10,
        status: event.status,
        dateFrom: event.dateFrom,
        dateTo: event.dateTo,
        search: event.search,
      );

      await result.fold(
        (failure) async {
          // On error, revert loading state but don't show error
          // Just silently fail and allow retry
          emit(currentState.copyWith(isLoadingMore: false));
          _isLoadingMore = false;
        },
        (response) async {
          final newOrders = response.data?.orders ?? [];

          // Prevent duplicate orders
          final currentOrderIds = currentState.orders.map((p) => p.id).toSet();
          final filteredNewOrders = newOrders
              .where((order) => !currentOrderIds.contains(order.id))
              .toList();

          final allOrders = List<Order>.from(currentState.orders)
            ..addAll(filteredNewOrders);

          final hasReachedMax = newOrders.length < 10;

          emit(_Loaded(
            orders: allOrders,
            totalOrder: response.data?.totalCount ?? 0,
            hasReachedMax: hasReachedMax,
            currentPage: nextPage,
            isLoadingMore: false,
          ));

          _isLoadingMore = false;
        },
      );
    } catch (e) {
      // Handle unexpected errors
      emit(currentState.copyWith(isLoadingMore: false));
      _isLoadingMore = false;
    }
  }

  // Refresh data
  Future<void> _onRefresh(
    _Refresh event,
    Emitter<OrderLoaderState> emit,
  ) async {
    _isLoadingMore = false;
    _loadMoreDebounce?.cancel();
    add(
      _GetByStatus(
        event.status,
        dateFrom: DateTime.now(),
        dateTo: DateTime.now(),
      ),
    );
  }
}
