import 'dart:async';
import 'dart:developer';
import 'package:enaklo_pos/data/models/response/category_response_model.dart';
import 'package:enaklo_pos/data/repositories/category/category_repository.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'category_loader_event.dart';
part 'category_loader_state.dart';
part 'category_loader_bloc.freezed.dart';

class CategoryLoaderBloc
    extends Bloc<CategoryLoaderEvent, CategoryLoaderState> {
  final CategoryRepository _categoryRepository = CategoryRepository.instance;

  Timer? _searchDebounce;
  bool _isLoadingMore = false;

  CategoryLoaderBloc() : super(const CategoryLoaderState.initial()) {
    on<_GetCategories>(_onGetCategories);
    on<_LoadMore>(_onLoadMore);
    on<_Refresh>(_onRefresh);
    on<_Search>(_onSearch);
    on<_SyncAll>(_onSyncAll);
    on<_GetAllCategories>(_onGetAllCategories);
    on<_ClearCache>(_onClearCache);
    on<_GetDatabaseStats>(_onGetDatabaseStats);
  }

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

  // ========================================
  // GET CATEGORIES (Remote-first with local fallback)
  // ========================================
  Future<void> _onGetCategories(
    _GetCategories event,
    Emitter<CategoryLoaderState> emit,
  ) async {
    emit(const CategoryLoaderState.loading());
    _isLoadingMore = false;

    log('📱 Loading categories - isActive: ${event.isActive}, forceRemote: ${event.forceRemote}');

    final result = await _categoryRepository.getCategories(
      page: 1,
      limit: 50,
      isActive: event.isActive,
      search: event.search,
      forceRemote: event.forceRemote,
    );

    await result.fold(
      (failure) async {
        log('❌ Error loading categories: $failure');
        emit(CategoryLoaderState.error(failure));
      },
      (response) async {
        final categories = [
          CategoryModel.all(),
          ...response.data.categories,
        ];

        final totalPages = response.data.totalPages;
        final hasReachedMax = categories.length < 50 || 1 >= totalPages;

        log('✅ Categories loaded: ${categories.length}, hasReachedMax: $hasReachedMax');

        emit(CategoryLoaderState.loaded(
          categories: categories,
          hasReachedMax: hasReachedMax,
          currentPage: 1,
          isLoadingMore: false,
          isActive: event.isActive,
          searchQuery: event.search,
        ));
      },
    );
  }

  // ========================================
  // LOAD MORE CATEGORIES
  // ========================================
  Future<void> _onLoadMore(
    _LoadMore event,
    Emitter<CategoryLoaderState> 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 categories - page: $nextPage');

    try {
      final result = await _categoryRepository.getCategories(
        page: nextPage,
        limit: 10,
        isActive: currentState.isActive,
        search: currentState.searchQuery,
      );

      await result.fold(
        (failure) async {
          log('❌ Error loading more categories: $failure');
          emit(currentState.copyWith(isLoadingMore: false));
        },
        (response) async {
          final newCategories = response.data.categories;
          final totalPages = response.data.totalPages;

          // Prevent duplicate categories
          final currentCategoryIds =
              currentState.categories.map((c) => c.id).toSet();
          final filteredNewCategories = newCategories
              .where((category) => !currentCategoryIds.contains(category.id))
              .toList();

          final allCategories =
              List<CategoryModel>.from(currentState.categories)
                ..addAll(filteredNewCategories);

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

          log('✅ More categories loaded: ${filteredNewCategories.length} new, total: ${allCategories.length}');

          emit(CategoryLoaderState.loaded(
            categories: allCategories,
            hasReachedMax: hasReachedMax,
            currentPage: nextPage,
            isLoadingMore: false,
            isActive: currentState.isActive,
            searchQuery: currentState.searchQuery,
          ));
        },
      );
    } catch (e) {
      log('❌ Exception loading more categories: $e');
      emit(currentState.copyWith(isLoadingMore: false));
    } finally {
      _isLoadingMore = false;
    }
  }

  // ========================================
  // REFRESH CATEGORIES
  // ========================================
  Future<void> _onRefresh(
    _Refresh event,
    Emitter<CategoryLoaderState> emit,
  ) async {
    final currentState = state;
    bool isActive = true;
    String? searchQuery;

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

    _isLoadingMore = false;
    _searchDebounce?.cancel();

    log('🔄 Refreshing categories');

    // Clear local cache
    _categoryRepository.clearCache();

    add(CategoryLoaderEvent.getCategories(
      isActive: isActive,
      search: searchQuery,
      forceRemote: true, // Force remote refresh
    ));
  }

  // ========================================
  // SEARCH CATEGORIES
  // ========================================
  Future<void> _onSearch(
    _Search event,
    Emitter<CategoryLoaderState> emit,
  ) async {
    // Cancel previous search
    _searchDebounce?.cancel();

    // Debounce search for better UX
    _searchDebounce = Timer(Duration(milliseconds: 300), () async {
      emit(const CategoryLoaderState.loading());
      _isLoadingMore = false;

      log('🔍 Searching categories: "${event.query}"');

      final result = await _categoryRepository.getCategories(
        page: 1,
        limit: 20, // More results for search
        isActive: event.isActive,
        search: event.query,
      );

      await result.fold(
        (failure) async {
          log('❌ Search error: $failure');
          emit(CategoryLoaderState.error(failure));
        },
        (response) async {
          final categories = response.data.categories;
          final totalPages = response.data.totalPages;
          final hasReachedMax = categories.length < 20 || 1 >= totalPages;

          log('✅ Search results: ${categories.length} categories found');

          emit(CategoryLoaderState.loaded(
            categories: categories,
            hasReachedMax: hasReachedMax,
            currentPage: 1,
            isLoadingMore: false,
            isActive: event.isActive,
            searchQuery: event.query,
          ));
        },
      );
    });
  }

  // ========================================
  // SYNC ALL CATEGORIES
  // ========================================
  Future<void> _onSyncAll(
    _SyncAll event,
    Emitter<CategoryLoaderState> emit,
  ) async {
    emit(const CategoryLoaderState.syncing());

    log('🔄 Starting full category sync...');

    final result = await _categoryRepository.syncAllCategories();

    await result.fold(
      (failure) async {
        log('❌ Sync failed: $failure');
        emit(CategoryLoaderState.syncError(failure));

        // After sync error, try to load local data
        Timer(Duration(seconds: 2), () {
          add(const CategoryLoaderEvent.getCategories());
        });
      },
      (successMessage) async {
        log('✅ Sync completed: $successMessage');
        emit(CategoryLoaderState.syncSuccess(successMessage));

        // After successful sync, load the updated data
        Timer(Duration(seconds: 1), () {
          add(const CategoryLoaderEvent.getCategories());
        });
      },
    );
  }

  // ========================================
  // GET ALL CATEGORIES (For Dropdown)
  // ========================================
  Future<void> _onGetAllCategories(
    _GetAllCategories event,
    Emitter<CategoryLoaderState> emit,
  ) async {
    try {
      log('📋 Loading all categories for dropdown...');

      final categories = await _categoryRepository.getAllCategories();

      emit(CategoryLoaderState.allCategoriesLoaded(categories));
      log('✅ All categories loaded: ${categories.length}');
    } catch (e) {
      log('❌ Error loading all categories: $e');
      emit(CategoryLoaderState.error('Gagal memuat semua kategori: $e'));
    }
  }

  // ========================================
  // GET DATABASE STATS
  // ========================================
  Future<void> _onGetDatabaseStats(
    _GetDatabaseStats event,
    Emitter<CategoryLoaderState> emit,
  ) async {
    try {
      final stats = await _categoryRepository.getDatabaseStats();
      log('📊 Category 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 category database stats: $e');
    }
  }

  // ========================================
  // CLEAR CACHE
  // ========================================
  Future<void> _onClearCache(
    _ClearCache event,
    Emitter<CategoryLoaderState> emit,
  ) async {
    log('🧹 Manually clearing category cache');
    _categoryRepository.clearCache();

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