import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:worker/core/network/dio_client.dart';
import 'package:worker/core/network/network_info.dart';
import 'package:worker/features/favorites/data/datasources/favorite_products_local_datasource.dart';
import 'package:worker/features/favorites/data/datasources/favorites_remote_datasource.dart';
import 'package:worker/features/favorites/data/repositories/favorites_repository_impl.dart';
import 'package:worker/features/favorites/domain/repositories/favorites_repository.dart';
import 'package:worker/features/products/domain/entities/product.dart';

part 'favorites_provider.g.dart';

// ============================================================================
// DATASOURCE PROVIDERS
// ============================================================================

/// Provides instance of FavoritesRemoteDataSource
@riverpod
Future<FavoritesRemoteDataSource> favoritesRemoteDataSource(Ref ref) async {
  final dioClient = await ref.watch(dioClientProvider.future);
  return FavoritesRemoteDataSource(dioClient.dio);
}

/// Provides instance of FavoriteProductsLocalDataSource
@riverpod
FavoriteProductsLocalDataSource favoriteProductsLocalDataSource(Ref ref) {
  return FavoriteProductsLocalDataSource();
}

// ============================================================================
// REPOSITORY PROVIDER
// ============================================================================

/// Provides instance of FavoritesRepository with online-first approach
@riverpod
Future<FavoritesRepository> favoritesRepository(Ref ref) async {
  final remoteDataSource = await ref.watch(favoritesRemoteDataSourceProvider.future);
  final productsLocalDataSource = ref.watch(favoriteProductsLocalDataSourceProvider);
  final networkInfo = ref.watch(networkInfoProvider);

  return FavoritesRepositoryImpl(
    remoteDataSource: remoteDataSource,
    productsLocalDataSource: productsLocalDataSource,
    networkInfo: networkInfo,
  );
}

// ============================================================================
// MAIN FAVORITE PRODUCTS PROVIDER
// ============================================================================

/// Manages favorite products with full Product data from wishlist API
///
/// This is the MAIN provider for the favorites feature.
/// Returns full Product objects with all data from the wishlist API.
///
/// Online-first: Fetches from API, caches locally
/// Offline: Returns cached products
///
/// Uses keepAlive to prevent unnecessary reloads.
/// Provides refresh() method for pull-to-refresh functionality.
///
/// AsyncNotifier pattern allows:
/// - Manual refresh capability
/// - Proper loading states during operations
/// - State updates after mutations
/// - Better error handling
@Riverpod(keepAlive: true)
class FavoriteProducts extends _$FavoriteProducts {
  late FavoritesRepository _repository;

  @override
  Future<List<Product>> build() async {
    _repository = await ref.read(favoritesRepositoryProvider.future);
    final products = await _loadProducts();

    // Sync local IDs after loading
    ref.read(favoriteIdsLocalProvider.notifier).refresh();

    return products;
  }

  // ==========================================================================
  // PRIVATE METHODS
  // ==========================================================================

  /// Load favorite products from repository
  ///
  /// Online-first: Fetches from API, caches locally
  /// Falls back to local cache on network failure
  Future<List<Product>> _loadProducts() async {
    try {
      final products = await _repository.getFavoriteProducts();
      _debugPrint('Loaded ${products.length} favorite products');
      return products;
    } catch (e) {
      _debugPrint('Error loading favorite products: $e');
      rethrow;
    }
  }

  // ==========================================================================
  // PUBLIC METHODS
  // ==========================================================================

  /// Add a product to favorites
  ///
  /// Calls API to add to wishlist, updates local state only (no refetch).
  /// No userId needed - the API uses the authenticated session.
  Future<void> addFavorite(String productId) async {
    try {
      _debugPrint('Adding product to favorites: $productId');

      // Optimistically update local state first for instant UI feedback
      ref.read(favoriteIdsLocalProvider.notifier).addId(productId);

      // Call repository to add to favorites (uses auth token from session)
      await _repository.addFavorite(productId);

      _debugPrint('Successfully added favorite: $productId');
    } catch (e) {
      // Rollback optimistic update on error
      ref.read(favoriteIdsLocalProvider.notifier).removeId(productId);
      _debugPrint('Error adding favorite: $e');
      rethrow;
    }
  }

  /// Remove a product from favorites
  ///
  /// Calls API to remove from wishlist, updates local state only (no refetch).
  /// No userId needed - the API uses the authenticated session.
  Future<void> removeFavorite(String productId) async {
    try {
      _debugPrint('Removing product from favorites: $productId');

      // Optimistically update local state first for instant UI feedback
      ref.read(favoriteIdsLocalProvider.notifier).removeId(productId);

      // Call repository to remove from favorites (uses auth token from session)
      await _repository.removeFavorite(productId);

      _debugPrint('Successfully removed favorite: $productId');
    } catch (e) {
      // Rollback optimistic update on error
      ref.read(favoriteIdsLocalProvider.notifier).addId(productId);
      _debugPrint('Error removing favorite: $e');
      rethrow;
    }
  }

  /// Toggle favorite status for a product
  ///
  /// If the product is favorited, it will be removed.
  /// If the product is not favorited, it will be added.
  /// Checks from local state for instant response.
  Future<void> toggleFavorite(String productId) async {
    // Check from local IDs (instant, no API call)
    final localIds = ref.read(favoriteIdsLocalProvider);
    final isFavorited = localIds.contains(productId);

    if (isFavorited) {
      await removeFavorite(productId);
    } else {
      await addFavorite(productId);
    }
  }

  /// Refresh favorite products from API
  ///
  /// Used for pull-to-refresh functionality.
  /// Fetches latest data from API and updates cache.
  Future<void> refresh() async {
    state = const AsyncValue.loading();
    state = await AsyncValue.guard(() async {
      return await _loadProducts();
    });
  }
}

// ============================================================================
// HELPER PROVIDERS
// ============================================================================

/// Check if a specific product is favorited (LOCAL ONLY - no API call)
///
/// Reads directly from Hive local cache for instant response.
/// This is used in product detail page to avoid unnecessary API calls.
/// The cache is synced when favorites are loaded or modified.
@riverpod
bool isFavorite(Ref ref, String productId) {
  // Watch the notifier state to trigger rebuild when favorites change
  // But check from local Hive directly for instant response
  ref.watch(favoriteIdsLocalProvider);

  final localDataSource = ref.read(favoriteProductsLocalDataSourceProvider);
  return localDataSource.isFavorite(productId);
}

/// Local favorite IDs provider (synced with Hive)
///
/// This provider watches Hive changes and provides a Set of favorite product IDs.
/// Used to trigger rebuilds when favorites are added/removed.
@Riverpod(keepAlive: true)
class FavoriteIdsLocal extends _$FavoriteIdsLocal {
  @override
  Set<String> build() {
    final localDataSource = ref.read(favoriteProductsLocalDataSourceProvider);
    return localDataSource.getFavoriteIds();
  }

  /// Refresh from local storage
  void refresh() {
    final localDataSource = ref.read(favoriteProductsLocalDataSourceProvider);
    state = localDataSource.getFavoriteIds();
  }

  /// Add a product ID to local state
  void addId(String productId) {
    state = {...state, productId};
  }

  /// Remove a product ID from local state
  void removeId(String productId) {
    state = {...state}..remove(productId);
  }
}

/// Get the total count of favorites
///
/// Derived from the favorite products list.
/// Returns the number of products in the user's favorites.
/// Safe to use in build methods - will return 0 during loading/error states.
@riverpod
int favoriteCount(Ref ref) {
  final favoriteProductsAsync = ref.watch(favoriteProductsProvider);

  return favoriteProductsAsync.when(
    data: (products) => products.length,
    loading: () => 0,
    error: (_, __) => 0,
  );
}

/// Get all favorite product IDs as a list
///
/// Derived from the favorite products list.
/// Useful for filtering product lists or bulk operations.
/// Returns an empty list during loading/error states.
@riverpod
List<String> favoriteProductIds(Ref ref) {
  final favoriteProductsAsync = ref.watch(favoriteProductsProvider);

  return favoriteProductsAsync.when(
    data: (products) => products.map((p) => p.productId).toList(),
    loading: () => <String>[],
    error: (_, __) => <String>[],
  );
}

// ============================================================================
// DEBUG UTILITIES
// ============================================================================

/// Debug print helper
void _debugPrint(String message) {
  // ignore: avoid_print
  print('[FavoritesProvider] $message');
}
