import 'dart:async';
import 'dart:developer';
import 'package:enaklo_pos/data/models/response/product_response_model.dart';
import 'package:enaklo_pos/data/repositories/product/product_repository.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

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

class ProductLoaderBloc extends Bloc<ProductLoaderEvent, ProductLoaderState> {
  final ProductRepository _productRepository = ProductRepository.instance;

  Timer? _loadMoreDebounce;
  Timer? _searchDebounce;
  bool _isLoadingMore = false;

  ProductLoaderBloc() : super(const ProductLoaderState.initial()) {
    on<_GetProduct>(_onGetProduct);
    on<_LoadMore>(_onLoadMore);
    on<_Refresh>(_onRefresh);
    on<_SearchProduct>(_onSearchProduct);
    on<_GetDatabaseStats>(_onGetDatabaseStats);
    on<_ClearCache>(_onClearCache);
  }

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

  // Pure local product loading
  Future<void> _onGetProduct(
    _GetProduct event,
    Emitter<ProductLoaderState> emit,
  ) async {
    emit(const ProductLoaderState.loading());
    _isLoadingMore = false;

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

    // Check if local database is ready
    final isReady = await _productRepository.isLocalDatabaseReady();
    if (!isReady) {
      emit(const ProductLoaderState.error(
          'Database lokal belum siap. Silakan lakukan sinkronisasi data terlebih dahulu.'));
      return;
    }

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

    await result.fold(
      (failure) async {
        log('❌ Error loading local products: $failure');
        emit(ProductLoaderState.error(failure));
      },
      (response) async {
        final products = response.data?.products ?? [];
        final totalPages = response.data?.totalPages ?? 1;
        final hasReachedMax = products.length < 10 || 1 >= totalPages;

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

        emit(ProductLoaderState.loaded(
          products: products,
          hasReachedMax: hasReachedMax,
          currentPage: 1,
          isLoadingMore: false,
          categoryId: event.categoryId,
          searchQuery: event.search,
        ));
      },
    );
  }

  // Pure local load more
  Future<void> _onLoadMore(
    _LoadMore event,
    Emitter<ProductLoaderState> emit,
  ) async {
    final currentState = state;

    if (currentState is! _Loaded ||
        currentState.hasReachedMax ||
        _isLoadingMore ||
        currentState.isLoadingMore) {
      log('⏹️ Load more blocked - state: ${currentState.runtimeType}, isLoadingMore: $_isLoadingMore');
      return;
    }

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

    final nextPage = currentState.currentPage + 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));
        },
        (response) async {
          final newProducts = response.data?.products ?? [];
          final totalPages = response.data?.totalPages ?? 1;

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

          final allProducts = List<Product>.from(currentState.products)
            ..addAll(filteredNewProducts);

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

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

          emit(ProductLoaderState.loaded(
            products: allProducts,
            hasReachedMax: hasReachedMax,
            currentPage: nextPage,
            isLoadingMore: false,
            categoryId: currentState.categoryId,
            searchQuery: currentState.searchQuery,
          ));
        },
      );
    } catch (e) {
      log('❌ Exception loading more local products: $e');
      emit(currentState.copyWith(isLoadingMore: false));
    } finally {
      _isLoadingMore = false;
    }
  }

  // Pure local refresh
  Future<void> _onRefresh(
    _Refresh event,
    Emitter<ProductLoaderState> emit,
  ) async {
    final currentState = state;
    String? categoryId;
    String? searchQuery;

    if (currentState is _Loaded) {
      categoryId = currentState.categoryId;
      searchQuery = currentState.searchQuery;
    }

    _isLoadingMore = false;
    _loadMoreDebounce?.cancel();
    _searchDebounce?.cancel();

    log('🔄 Refreshing local products');

    // Clear local cache
    _productRepository.clearCache();

    add(ProductLoaderEvent.getProduct(
      categoryId: categoryId,
      search: searchQuery,
    ));
  }

  // Fast local search (no debouncing needed for local data)
  Future<void> _onSearchProduct(
    _SearchProduct event,
    Emitter<ProductLoaderState> emit,
  ) async {
    // Cancel previous search
    _searchDebounce?.cancel();

    // Minimal debounce for local search (much faster)
    _searchDebounce = Timer(Duration(milliseconds: 150), () async {
      emit(const ProductLoaderState.loading());
      _isLoadingMore = false;

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

      final result = await _productRepository.getProducts(
        page: 1,
        limit: 20, // More results for search
        categoryId: event.categoryId,
        search: event.query,
      );

      await result.fold(
        (failure) async {
          log('❌ Local search error: $failure');
          emit(ProductLoaderState.error(failure));
        },
        (response) async {
          final products = response.data?.products ?? [];
          final totalPages = response.data?.totalPages ?? 1;
          final hasReachedMax = products.length < 20 || 1 >= totalPages;

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

          emit(ProductLoaderState.loaded(
            products: products,
            hasReachedMax: hasReachedMax,
            currentPage: 1,
            isLoadingMore: false,
            categoryId: event.categoryId,
            searchQuery: event.query,
          ));
        },
      );
    });
  }

  // Get local database statistics
  Future<void> _onGetDatabaseStats(
    _GetDatabaseStats event,
    Emitter<ProductLoaderState> emit,
  ) async {
    try {
      final stats = await _productRepository.getDatabaseStats();
      log('📊 Local database stats retrieved: $stats');

      // You can emit a special state here if needed for UI updates
      // For now, just log the stats
    } catch (e) {
      log('❌ Error getting local database stats: $e');
    }
  }

  // Clear local cache
  Future<void> _onClearCache(
    _ClearCache event,
    Emitter<ProductLoaderState> emit,
  ) async {
    log('🧹 Manually clearing local cache');
    _productRepository.clearCache();

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