import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../../features/auth/data/datasources/auth_remote_datasource.dart';
import '../../features/auth/data/repositories/auth_repository_impl.dart';
import '../../features/auth/domain/repositories/auth_repository.dart';
import '../../features/auth/domain/usecases/login_usecase.dart';
import '../../features/auth/presentation/providers/auth_provider.dart';
import '../../features/products/data/datasources/products_local_datasource.dart';
import '../../features/products/data/datasources/products_remote_datasource.dart';
import '../../features/products/data/repositories/products_repository_impl.dart';
import '../../features/products/domain/entities/product_stage_entity.dart';
import '../../features/products/domain/repositories/products_repository.dart';
import '../../features/products/domain/usecases/get_product_detail_usecase.dart';
import '../../features/products/domain/usecases/get_products_usecase.dart';
import '../../features/products/presentation/providers/product_detail_provider.dart';
import '../../features/products/presentation/providers/products_provider.dart';
import '../../features/warehouse/data/datasources/warehouse_remote_datasource.dart';
import '../../features/warehouse/data/repositories/warehouse_repository_impl.dart';
import '../../features/warehouse/domain/repositories/warehouse_repository.dart';
import '../../features/warehouse/domain/usecases/get_warehouses_usecase.dart';
import '../../features/warehouse/presentation/providers/warehouse_provider.dart';
import '../../features/users/data/datasources/users_local_datasource.dart';
import '../../features/users/data/datasources/users_remote_datasource.dart';
import '../../features/users/data/repositories/users_repository_impl.dart';
import '../../features/users/domain/repositories/users_repository.dart';
import '../../features/users/domain/usecases/get_users_usecase.dart';
import '../../features/users/domain/usecases/sync_users_usecase.dart';
import '../../features/users/presentation/providers/users_provider.dart';
import '../../features/users/presentation/providers/users_state.dart';
import '../network/api_client.dart';
import '../storage/secure_storage.dart';

/// ========================================================================
/// CORE PROVIDERS
/// ========================================================================
/// These are singleton providers for core infrastructure services

/// Secure storage provider (Singleton)
/// Provides secure storage for sensitive data like tokens
final secureStorageProvider = Provider<SecureStorage>((ref) {
  return SecureStorage();
});

/// API client provider (Singleton)
/// Provides HTTP client with authentication and error handling
/// Depends on SecureStorage for token management
final apiClientProvider = Provider<ApiClient>((ref) {
  final secureStorage = ref.watch(secureStorageProvider);
  return ApiClient(secureStorage);
});

/// ========================================================================
/// AUTH FEATURE PROVIDERS
/// ========================================================================
/// Providers for authentication feature following clean architecture

// Data Layer

/// Auth remote data source provider
/// Handles API calls for authentication
final authRemoteDataSourceProvider = Provider<AuthRemoteDataSource>((ref) {
  final apiClient = ref.watch(apiClientProvider);
  return AuthRemoteDataSourceImpl(apiClient);
});

/// Auth repository provider
/// Implements domain repository interface
/// Coordinates between data sources and handles error conversion
final authRepositoryProvider = Provider<AuthRepository>((ref) {
  final remoteDataSource = ref.watch(authRemoteDataSourceProvider);
  final secureStorage = ref.watch(secureStorageProvider);
  return AuthRepositoryImpl(
    remoteDataSource: remoteDataSource,
    secureStorage: secureStorage,
  );
});

// Domain Layer

/// Login use case provider
/// Encapsulates login business logic
final loginUseCaseProvider = Provider<LoginUseCase>((ref) {
  final repository = ref.watch(authRepositoryProvider);
  return LoginUseCase(repository);
});

/// Logout use case provider
/// Encapsulates logout business logic
final logoutUseCaseProvider = Provider<LogoutUseCase>((ref) {
  final repository = ref.watch(authRepositoryProvider);
  return LogoutUseCase(repository);
});

/// Check auth status use case provider
/// Checks if user is authenticated
final checkAuthStatusUseCaseProvider = Provider<CheckAuthStatusUseCase>((ref) {
  final repository = ref.watch(authRepositoryProvider);
  return CheckAuthStatusUseCase(repository);
});

/// Get current user use case provider
/// Retrieves current user data from storage
final getCurrentUserUseCaseProvider = Provider<GetCurrentUserUseCase>((ref) {
  final repository = ref.watch(authRepositoryProvider);
  return GetCurrentUserUseCase(repository);
});

/// Refresh token use case provider
/// Refreshes access token using refresh token
final refreshTokenUseCaseProvider = Provider<RefreshTokenUseCase>((ref) {
  final repository = ref.watch(authRepositoryProvider);
  return RefreshTokenUseCase(repository);
});

// Presentation Layer

/// Auth state notifier provider
/// Manages authentication state across the app
/// This is the main provider to use in UI for auth state
final authProvider = StateNotifierProvider<AuthNotifier, AuthState>((ref) {
  final loginUseCase = ref.watch(loginUseCaseProvider);
  final logoutUseCase = ref.watch(logoutUseCaseProvider);
  final checkAuthStatusUseCase = ref.watch(checkAuthStatusUseCaseProvider);
  final getCurrentUserUseCase = ref.watch(getCurrentUserUseCaseProvider);

  return AuthNotifier(
    loginUseCase: loginUseCase,
    logoutUseCase: logoutUseCase,
    checkAuthStatusUseCase: checkAuthStatusUseCase,
    getCurrentUserUseCase: getCurrentUserUseCase,
  );
});

/// Convenient providers for auth state

/// Provider to check if user is authenticated
/// Usage: ref.watch(isAuthenticatedProvider)
final isAuthenticatedProvider = Provider<bool>((ref) {
  final authState = ref.watch(authProvider);
  return authState.isAuthenticated;
});

/// Provider to get current user
/// Returns null if user is not authenticated
/// Usage: ref.watch(currentUserProvider)
final currentUserProvider = Provider((ref) {
  final authState = ref.watch(authProvider);
  return authState.user;
});

/// Provider to check if auth is loading
/// Usage: ref.watch(isAuthLoadingProvider)
final isAuthLoadingProvider = Provider<bool>((ref) {
  final authState = ref.watch(authProvider);
  return authState.isLoading;
});

/// Provider to get auth error
/// Returns null if no error
/// Usage: ref.watch(authErrorProvider)
final authErrorProvider = Provider<String?>((ref) {
  final authState = ref.watch(authProvider);
  return authState.error;
});

/// ========================================================================
/// WAREHOUSE FEATURE PROVIDERS
/// ========================================================================
/// Providers for warehouse feature following clean architecture

// Data Layer

/// Warehouse remote data source provider
/// Handles API calls for warehouses
final warehouseRemoteDataSourceProvider =
    Provider<WarehouseRemoteDataSource>((ref) {
  final apiClient = ref.watch(apiClientProvider);
  return WarehouseRemoteDataSourceImpl(apiClient);
});

/// Warehouse repository provider
/// Implements domain repository interface
final warehouseRepositoryProvider = Provider<WarehouseRepository>((ref) {
  final remoteDataSource = ref.watch(warehouseRemoteDataSourceProvider);
  return WarehouseRepositoryImpl(remoteDataSource);
});

// Domain Layer

/// Get warehouses use case provider
/// Encapsulates warehouse fetching business logic
final getWarehousesUseCaseProvider = Provider<GetWarehousesUseCase>((ref) {
  final repository = ref.watch(warehouseRepositoryProvider);
  return GetWarehousesUseCase(repository);
});

// Presentation Layer

/// Warehouse state notifier provider
/// Manages warehouse state including list and selection
final warehouseProvider =
    StateNotifierProvider<WarehouseNotifier, WarehouseState>((ref) {
  final getWarehousesUseCase = ref.watch(getWarehousesUseCaseProvider);
  return WarehouseNotifier(getWarehousesUseCase);
});

/// Convenient providers for warehouse state

/// Provider to get list of warehouses
/// Usage: ref.watch(warehousesListProvider)
final warehousesListProvider = Provider((ref) {
  final warehouseState = ref.watch(warehouseProvider);
  return warehouseState.warehouses;
});

/// Provider to get selected warehouse
/// Returns null if no warehouse is selected
/// Usage: ref.watch(selectedWarehouseProvider)
final selectedWarehouseProvider = Provider((ref) {
  final warehouseState = ref.watch(warehouseProvider);
  return warehouseState.selectedWarehouse;
});

/// Provider to check if warehouses are loading
/// Usage: ref.watch(isWarehouseLoadingProvider)
final isWarehouseLoadingProvider = Provider<bool>((ref) {
  final warehouseState = ref.watch(warehouseProvider);
  return warehouseState.isLoading;
});

/// Provider to check if warehouses have been loaded
/// Usage: ref.watch(hasWarehousesProvider)
final hasWarehousesProvider = Provider<bool>((ref) {
  final warehouseState = ref.watch(warehouseProvider);
  return warehouseState.hasWarehouses;
});

/// Provider to check if a warehouse is selected
/// Usage: ref.watch(hasWarehouseSelectionProvider)
final hasWarehouseSelectionProvider = Provider<bool>((ref) {
  final warehouseState = ref.watch(warehouseProvider);
  return warehouseState.hasSelection;
});

/// Provider to get warehouse error
/// Returns null if no error
/// Usage: ref.watch(warehouseErrorProvider)
final warehouseErrorProvider = Provider<String?>((ref) {
  final warehouseState = ref.watch(warehouseProvider);
  return warehouseState.error;
});

/// ========================================================================
/// PRODUCTS FEATURE PROVIDERS
/// ========================================================================
/// Providers for products feature following clean architecture

// Data Layer

/// Products local data source provider
/// Handles local storage operations for products using Hive
final productsLocalDataSourceProvider = Provider<ProductsLocalDataSource>((ref) {
  return ProductsLocalDataSourceImpl();
});

/// Products remote data source provider
/// Handles API calls for products
final productsRemoteDataSourceProvider =
    Provider<ProductsRemoteDataSource>((ref) {
  final apiClient = ref.watch(apiClientProvider);
  return ProductsRemoteDataSourceImpl(apiClient);
});

/// Products repository provider
/// Implements domain repository interface
/// Coordinates between local and remote data sources
final productsRepositoryProvider = Provider<ProductsRepository>((ref) {
  final remoteDataSource = ref.watch(productsRemoteDataSourceProvider);
  final localDataSource = ref.watch(productsLocalDataSourceProvider);
  return ProductsRepositoryImpl(
    remoteDataSource: remoteDataSource,
    localDataSource: localDataSource,
  );
});

// Domain Layer

/// Get products use case provider
/// Encapsulates product fetching business logic
final getProductsUseCaseProvider = Provider<GetProductsUseCase>((ref) {
  final repository = ref.watch(productsRepositoryProvider);
  return GetProductsUseCase(repository);
});

/// Get product detail use case provider
/// Encapsulates product detail fetching business logic
final getProductDetailUseCaseProvider = Provider<GetProductDetailUseCase>((ref) {
  final repository = ref.watch(productsRepositoryProvider);
  return GetProductDetailUseCase(repository);
});

// Presentation Layer

/// Products state notifier provider
/// Manages products state including list, loading, and errors
final productsProvider =
    StateNotifierProvider<ProductsNotifier, ProductsState>((ref) {
  final getProductsUseCase = ref.watch(getProductsUseCaseProvider);
  return ProductsNotifier(getProductsUseCase);
});

/// Convenient providers for products state

/// Provider to get list of products
/// Usage: ref.watch(productsListProvider)
final productsListProvider = Provider((ref) {
  final productsState = ref.watch(productsProvider);
  return productsState.products;
});

/// Provider to get operation type (import/export)
/// Usage: ref.watch(operationTypeProvider)
final operationTypeProvider = Provider<String>((ref) {
  final productsState = ref.watch(productsProvider);
  return productsState.operationType;
});

/// Provider to get warehouse ID for products
/// Returns null if no warehouse is set
/// Usage: ref.watch(productsWarehouseIdProvider)
final productsWarehouseIdProvider = Provider<int?>((ref) {
  final productsState = ref.watch(productsProvider);
  return productsState.warehouseId;
});

/// Provider to get warehouse name for products
/// Returns null if no warehouse is set
/// Usage: ref.watch(productsWarehouseNameProvider)
final productsWarehouseNameProvider = Provider<String?>((ref) {
  final productsState = ref.watch(productsProvider);
  return productsState.warehouseName;
});

/// Provider to check if products are loading
/// Usage: ref.watch(isProductsLoadingProvider)
final isProductsLoadingProvider = Provider<bool>((ref) {
  final productsState = ref.watch(productsProvider);
  return productsState.isLoading;
});

/// Provider to check if products list has items
/// Usage: ref.watch(hasProductsProvider)
final hasProductsProvider = Provider<bool>((ref) {
  final productsState = ref.watch(productsProvider);
  return productsState.products.isNotEmpty;
});

/// Provider to get products count
/// Usage: ref.watch(productsCountProvider)
final productsCountProvider = Provider<int>((ref) {
  final productsState = ref.watch(productsProvider);
  return productsState.products.length;
});

/// Provider to get products error
/// Returns null if no error
/// Usage: ref.watch(productsErrorProvider)
final productsErrorProvider = Provider<String?>((ref) {
  final productsState = ref.watch(productsProvider);
  return productsState.error;
});

/// Product detail state notifier provider
/// Manages product detail state for a specific product in a warehouse
/// This needs to be a family provider to support multiple product details
final productDetailProvider =
    StateNotifierProvider.family<ProductDetailNotifier, ProductDetailState, String>(
  (ref, _) {
    final getProductDetailUseCase = ref.watch(getProductDetailUseCaseProvider);
    return ProductDetailNotifier(getProductDetailUseCase);
  },
);

/// Convenient providers for product detail state

/// Provider to get product stages list
/// Usage: ref.watch(productStagesProvider(key))
final productStagesProvider = Provider.family<List<ProductStageEntity>, String>((ref, key) {
  final state = ref.watch(productDetailProvider(key));
  return state.stages;
});

/// Provider to get selected product stage
/// Usage: ref.watch(selectedProductStageProvider(key))
final selectedProductStageProvider = Provider.family<ProductStageEntity?, String>((ref, key) {
  final state = ref.watch(productDetailProvider(key));
  return state.selectedStage;
});

/// Provider to check if product detail is loading
/// Usage: ref.watch(isProductDetailLoadingProvider(key))
final isProductDetailLoadingProvider = Provider.family<bool, String>((ref, key) {
  final state = ref.watch(productDetailProvider(key));
  return state.isLoading;
});

/// Provider to get product detail error
/// Returns null if no error
/// Usage: ref.watch(productDetailErrorProvider(key))
final productDetailErrorProvider = Provider.family<String?, String>((ref, key) {
  final state = ref.watch(productDetailProvider(key));
  return state.error;
});

/// ========================================================================
/// USERS FEATURE PROVIDERS
/// ========================================================================
/// Providers for users feature following clean architecture

// Data Layer

/// Users local data source provider
/// Handles local storage operations for users using Hive
final usersLocalDataSourceProvider = Provider<UsersLocalDataSource>((ref) {
  return UsersLocalDataSourceImpl();
});

/// Users remote data source provider
/// Handles API calls for users
final usersRemoteDataSourceProvider = Provider<UsersRemoteDataSource>((ref) {
  final apiClient = ref.watch(apiClientProvider);
  return UsersRemoteDataSourceImpl(apiClient);
});

/// Users repository provider
/// Implements domain repository interface
/// Coordinates between local and remote data sources
final usersRepositoryProvider = Provider<UsersRepository>((ref) {
  final remoteDataSource = ref.watch(usersRemoteDataSourceProvider);
  final localDataSource = ref.watch(usersLocalDataSourceProvider);
  return UsersRepositoryImpl(
    remoteDataSource: remoteDataSource,
    localDataSource: localDataSource,
  );
});

// Domain Layer

/// Get users use case provider
/// Encapsulates user fetching business logic (local-first strategy)
final getUsersUseCaseProvider = Provider<GetUsersUseCase>((ref) {
  final repository = ref.watch(usersRepositoryProvider);
  return GetUsersUseCase(repository);
});

/// Sync users use case provider
/// Encapsulates user syncing business logic (force refresh from API)
final syncUsersUseCaseProvider = Provider<SyncUsersUseCase>((ref) {
  final repository = ref.watch(usersRepositoryProvider);
  return SyncUsersUseCase(repository);
});

// Presentation Layer

/// Users state notifier provider
/// Manages users state including list, loading, and errors
final usersProvider = StateNotifierProvider<UsersNotifier, UsersState>((ref) {
  final getUsersUseCase = ref.watch(getUsersUseCaseProvider);
  final syncUsersUseCase = ref.watch(syncUsersUseCaseProvider);
  return UsersNotifier(
    getUsersUseCase: getUsersUseCase,
    syncUsersUseCase: syncUsersUseCase,
  );
});

/// Convenient providers for users state

/// Provider to get list of users
/// Usage: ref.watch(usersListProvider)
final usersListProvider = Provider((ref) {
  final usersState = ref.watch(usersProvider);
  return usersState.users;
});

/// Provider to check if users are loading
/// Usage: ref.watch(isUsersLoadingProvider)
final isUsersLoadingProvider = Provider<bool>((ref) {
  final usersState = ref.watch(usersProvider);
  return usersState.isLoading;
});

/// Provider to check if users list has items
/// Usage: ref.watch(hasUsersProvider)
final hasUsersProvider = Provider<bool>((ref) {
  final usersState = ref.watch(usersProvider);
  return usersState.users.isNotEmpty;
});

/// Provider to get users count
/// Usage: ref.watch(usersCountProvider)
final usersCountProvider = Provider<int>((ref) {
  final usersState = ref.watch(usersProvider);
  return usersState.users.length;
});

/// Provider to get users error
/// Returns null if no error
/// Usage: ref.watch(usersErrorProvider)
final usersErrorProvider = Provider<String?>((ref) {
  final usersState = ref.watch(usersProvider);
  return usersState.error;
});

/// ========================================================================
/// USAGE EXAMPLES
/// ========================================================================
///
/// 1. Authentication Example:
/// ```dart
/// // In your LoginPage
/// class LoginPage extends ConsumerWidget {
///   @override
///   Widget build(BuildContext context, WidgetRef ref) {
///     final isAuthenticated = ref.watch(isAuthenticatedProvider);
///     final isLoading = ref.watch(isAuthLoadingProvider);
///     final error = ref.watch(authErrorProvider);
///
///     return Scaffold(
///       body: Column(
///         children: [
///           if (error != null) Text(error, style: errorStyle),
///           ElevatedButton(
///             onPressed: isLoading
///                 ? null
///                 : () => ref.read(authProvider.notifier).login(
///                       username,
///                       password,
///                     ),
///             child: isLoading ? CircularProgressIndicator() : Text('Login'),
///           ),
///         ],
///       ),
///     );
///   }
/// }
/// ```
///
/// 2. Warehouse Selection Example:
/// ```dart
/// // In your WarehouseSelectionPage
/// class WarehouseSelectionPage extends ConsumerWidget {
///   @override
///   Widget build(BuildContext context, WidgetRef ref) {
///     final warehouses = ref.watch(warehousesListProvider);
///     final isLoading = ref.watch(isWarehouseLoadingProvider);
///     final selectedWarehouse = ref.watch(selectedWarehouseProvider);
///
///     // Load warehouses on first build
///     ref.listen(warehouseProvider, (previous, next) {
///       if (previous?.warehouses.isEmpty ?? true && !next.isLoading) {
///         ref.read(warehouseProvider.notifier).loadWarehouses();
///       }
///     });
///
///     return Scaffold(
///       body: isLoading
///           ? CircularProgressIndicator()
///           : ListView.builder(
///               itemCount: warehouses.length,
///               itemBuilder: (context, index) {
///                 final warehouse = warehouses[index];
///                 return ListTile(
///                   title: Text(warehouse.name),
///                   selected: selectedWarehouse?.id == warehouse.id,
///                   onTap: () {
///                     ref.read(warehouseProvider.notifier)
///                         .selectWarehouse(warehouse);
///                   },
///                 );
///               },
///             ),
///     );
///   }
/// }
/// ```
///
/// 3. Products List Example:
/// ```dart
/// // In your ProductsPage
/// class ProductsPage extends ConsumerWidget {
///   final int warehouseId;
///   final String warehouseName;
///   final String operationType;
///
///   const ProductsPage({
///     required this.warehouseId,
///     required this.warehouseName,
///     required this.operationType,
///   });
///
///   @override
///   Widget build(BuildContext context, WidgetRef ref) {
///     final products = ref.watch(productsListProvider);
///     final isLoading = ref.watch(isProductsLoadingProvider);
///     final error = ref.watch(productsErrorProvider);
///
///     // Load products on first build
///     useEffect(() {
///       ref.read(productsProvider.notifier).loadProducts(
///             warehouseId,
///             warehouseName,
///             operationType,
///           );
///       return null;
///     }, []);
///
///     return Scaffold(
///       appBar: AppBar(
///         title: Text('$warehouseName - $operationType'),
///       ),
///       body: isLoading
///           ? CircularProgressIndicator()
///           : error != null
///               ? Text(error)
///               : ListView.builder(
///                   itemCount: products.length,
///                   itemBuilder: (context, index) {
///                     final product = products[index];
///                     return ListTile(
///                       title: Text(product.name),
///                       subtitle: Text(product.code),
///                     );
///                   },
///                 ),
///     );
///   }
/// }
/// ```
///
/// 4. Checking Auth Status on App Start:
/// ```dart
/// // In your main.dart or root widget
/// class App extends ConsumerWidget {
///   @override
///   Widget build(BuildContext context, WidgetRef ref) {
///     // Check auth status when app starts
///     useEffect(() {
///       ref.read(authProvider.notifier).checkAuthStatus();
///       return null;
///     }, []);
///
///     final isAuthenticated = ref.watch(isAuthenticatedProvider);
///
///     return MaterialApp(
///       home: isAuthenticated ? WarehouseSelectionPage() : LoginPage(),
///     );
///   }
/// }
/// ```
///
/// 5. Logout Example:
/// ```dart
/// // In any widget
/// ElevatedButton(
///   onPressed: () {
///     ref.read(authProvider.notifier).logout();
///   },
///   child: Text('Logout'),
/// )
/// ```
///
/// ========================================================================
/// ARCHITECTURE NOTES
/// ========================================================================
///
/// This DI setup follows Clean Architecture principles:
///
/// 1. **Separation of Concerns**:
///    - Data Layer: Handles API calls and data storage
///    - Domain Layer: Contains business logic and use cases
///    - Presentation Layer: Manages UI state
///
/// 2. **Dependency Direction**:
///    - Presentation depends on Domain
///    - Data depends on Domain
///    - Domain depends on nothing (pure business logic)
///
/// 3. **Provider Hierarchy**:
///    - Core providers (Storage, API) are singletons
///    - Data sources depend on API client
///    - Repositories depend on data sources
///    - Use cases depend on repositories
///    - State notifiers depend on use cases
///
/// 4. **State Management**:
///    - StateNotifierProvider for mutable state
///    - Provider for immutable dependencies
///    - Convenient providers for derived state
///
/// 5. **Testability**:
///    - All dependencies are injected
///    - Easy to mock for testing
///    - Each layer can be tested independently
///
/// 6. **Scalability**:
///    - Add new features by following the same pattern
///    - Clear structure for team collaboration
///    - Easy to understand and maintain
///
