import 'dart:async';
import 'dart:developer';

import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';

import '../../../domain/product/product.dart';

part 'product_loader_event.dart';
part 'product_loader_state.dart';
part 'product_loader_bloc.freezed.dart';

@injectable
class ProductLoaderBloc extends Bloc<ProductLoaderEvent, ProductLoaderState> {
  final IProductRepository _productRepository;

  Timer? _loadMoreDebounce;
  Timer? _searchDebounce;

  ProductLoaderBloc(this._productRepository)
    : super(ProductLoaderState.initial()) {
    on<ProductLoaderEvent>(_onProductLoaderEvent);
  }

  Future<void> _onProductLoaderEvent(
    ProductLoaderEvent event,
    Emitter<ProductLoaderState> emit,
  ) {
    return event.map(
      getProduct: (e) async {
        emit(state.copyWith(isLoadingMore: true));

        log(
          '📱 Loading local products - categoryId: ${e.categoryId}, search: ${e.search}',
        );

        // Pastikan database lokal sudah siap
        final isReady = await _productRepository.isLocalDatabaseReady();
        if (!isReady) {
          emit(
            state.copyWith(
              isLoadingMore: false,
              failureOptionProduct: optionOf(
                const ProductFailure.dynamicErrorMessage(
                  'Database lokal belum siap. Silakan lakukan sinkronisasi data terlebih dahulu.',
                ),
              ),
            ),
          );
          return;
        }

        final result = await _productRepository.getProducts(
          page: 1,
          limit: 10,
          categoryId: e.categoryId,
          search: e.search,
        );

        await result.fold(
          (failure) async {
            log('❌ Error loading local products: $failure');
            emit(
              state.copyWith(
                isLoadingMore: false,
                failureOptionProduct: optionOf(failure),
              ),
            );
          },
          (response) async {
            final products = response.products;
            final totalPages = response.totalPages;
            final hasReachedMax = products.length < 10 || 1 >= totalPages;

            log(
              '✅ Local products loaded: ${products.length}, hasReachedMax: $hasReachedMax, totalPages: $totalPages',
            );

            emit(
              state.copyWith(
                products: products,
                page: 1,
                hasReachedMax: hasReachedMax,
                isLoadingMore: false,
                failureOptionProduct: none(),
                categoryId: e.categoryId,
                searchQuery: e.search,
              ),
            );
          },
        );
      },
      loadMore: (e) async {
        final currentState = state;

        // Cegah double load
        if (currentState.isLoadingMore || currentState.hasReachedMax) {
          log(
            '⏹️ Load more blocked - isLoadingMore: ${currentState.isLoadingMore}, hasReachedMax: ${currentState.hasReachedMax}',
          );
          return;
        }

        emit(currentState.copyWith(isLoadingMore: true));

        final nextPage = currentState.page + 1;
        log('📄 Loading more local products - page: $nextPage');

        try {
          final result = await _productRepository.getProducts(
            page: nextPage,
            limit: 10,
            categoryId: currentState.categoryId,
            search: currentState.searchQuery,
          );

          await result.fold(
            (failure) async {
              log('❌ Error loading more local products: $failure');
              emit(
                currentState.copyWith(
                  isLoadingMore: false,
                  failureOptionProduct: optionOf(failure),
                ),
              );
            },
            (response) async {
              final newProducts = response.products;
              final totalPages = response.totalPages;

              // Hindari duplikat produk
              final currentProductIds = currentState.products
                  .map((p) => p.id)
                  .toSet();
              final filteredNewProducts = newProducts
                  .where((product) => !currentProductIds.contains(product.id))
                  .toList();

              final allProducts = [
                ...currentState.products,
                ...filteredNewProducts,
              ];

              final hasReachedMax =
                  filteredNewProducts.length < 10 || nextPage >= totalPages;

              log(
                '✅ More local products loaded: ${filteredNewProducts.length} new, total: ${allProducts.length}, hasReachedMax: $hasReachedMax',
              );

              emit(
                currentState.copyWith(
                  products: allProducts,
                  page: nextPage,
                  hasReachedMax: hasReachedMax,
                  isLoadingMore: false,
                  failureOptionProduct: none(),
                ),
              );
            },
          );
        } catch (e) {
          log('❌ Exception loading more local products: $e');
          emit(
            currentState.copyWith(
              isLoadingMore: false,
              failureOptionProduct: optionOf(
                ProductFailure.dynamicErrorMessage(
                  'Gagal memuat produk tambahan: $e',
                ),
              ),
            ),
          );
        }
      },
      refresh: (e) async {
        final categoryId = state.categoryId;
        final searchQuery = state.searchQuery;

        _loadMoreDebounce?.cancel();
        _searchDebounce?.cancel();

        log(
          '🔄 Refreshing local products - categoryId: $categoryId, search: $searchQuery',
        );

        emit(state.copyWith(isLoadingMore: true));

        try {
          _productRepository.clearCache();

          final result = await _productRepository.refreshProducts(
            categoryId: categoryId,
            search: searchQuery,
          );

          await result.fold(
            (failure) async {
              log('❌ Failed to refresh local products: $failure');
              emit(
                state.copyWith(
                  isLoadingMore: false,
                  failureOptionProduct: optionOf(failure),
                ),
              );
            },
            (response) async {
              final products = response.products;
              final totalPages = response.totalPages;
              final hasReachedMax = products.length < 10 || 1 >= totalPages;

              log('✅ Refreshed local products: ${products.length}');

              emit(
                state.copyWith(
                  products: products,
                  hasReachedMax: hasReachedMax,
                  page: 1,
                  isLoadingMore: false,
                  failureOptionProduct: none(),
                  categoryId: categoryId,
                  searchQuery: searchQuery,
                ),
              );
            },
          );
        } catch (e) {
          log('❌ Exception refreshing local products: $e');
          emit(
            state.copyWith(
              isLoadingMore: false,
              failureOptionProduct: optionOf(
                ProductFailure.dynamicErrorMessage(e.toString()),
              ),
            ),
          );
        } finally {}
      },
      searchProduct: (e) async {
        _searchDebounce?.cancel();

        // Debounce ringan agar UX lebih halus
        _searchDebounce = Timer(const Duration(milliseconds: 150), () async {
          emit(state.copyWith(isLoadingMore: true));

          log('🔍 Local search: "${e.query}"');

          try {
            final result = await _productRepository.getProducts(
              page: 1,
              limit: 20, // lebih banyak hasil untuk pencarian
              categoryId: e.categoryId,
              search: e.query,
            );

            await result.fold(
              (failure) async {
                log('❌ Local search error: $failure');
                emit(
                  state.copyWith(
                    isLoadingMore: false,
                    failureOptionProduct: optionOf(failure),
                  ),
                );
              },
              (response) async {
                final products = response.products;
                final totalPages = response.totalPages;
                final hasReachedMax = products.length < 20 || 1 >= totalPages;

                log(
                  '✅ Local search results: ${products.length} products found',
                );

                emit(
                  state.copyWith(
                    products: products,
                    hasReachedMax: hasReachedMax,
                    page: 1,
                    isLoadingMore: false,
                    categoryId: e.categoryId,
                    searchQuery: e.query,
                    failureOptionProduct: none(),
                  ),
                );
              },
            );
          } catch (e) {
            log('❌ Exception during local search: $e');
            emit(
              state.copyWith(
                isLoadingMore: false,
                failureOptionProduct: optionOf(
                  ProductFailure.dynamicErrorMessage(e.toString()),
                ),
              ),
            );
          }
        });
      },
      getDatabaseStats: (e) async {
        log('📊 Getting local database stats...');

        try {
          final result = await _productRepository.getDatabaseStats();

          await result.fold(
            (failure) async {
              log('❌ Failed to get database stats: $failure');
              emit(state.copyWith(failureOptionProduct: optionOf(failure)));
            },
            (stats) async {
              log('✅ Local database stats retrieved: $stats');
              // Jika UI kamu perlu tampilkan, bisa simpan ke state, misalnya:
              // emit(state.copyWith(databaseStats: some(stats)));
              // Tapi kalau hanya untuk log/debug, tidak perlu ubah state
            },
          );
        } catch (e, s) {
          log(
            '❌ Exception while getting database stats: $e',
            error: e,
            stackTrace: s,
          );
          emit(
            state.copyWith(
              failureOptionProduct: optionOf(
                ProductFailure.dynamicErrorMessage(e.toString()),
              ),
            ),
          );
        }
      },
      clearCache: (e) async {
        log('🧹 Manually clearing local cache');
        _productRepository.clearCache();

        // Refresh current data after cache clear
        add(const ProductLoaderEvent.refresh());
      },
    );
  }
}
