import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'connectivity_provider.g.dart';

/// Enum representing connectivity status
enum ConnectivityStatus {
  /// Connected to WiFi
  wifi,

  /// Connected to mobile data
  mobile,

  /// No internet connection
  offline,
}

/// Provider for the Connectivity instance
/// This is a simple provider that returns a singleton instance
@riverpod
Connectivity connectivity(Ref ref) {
  return Connectivity();
}

/// Stream provider that monitors real-time connectivity changes
/// This automatically updates whenever the device connectivity changes
///
/// Usage:
/// ```dart
/// final connectivityState = ref.watch(connectivityStreamProvider);
/// connectivityState.when(
///   data: (status) => Text('Status: $status'),
///   loading: () => const CustomLoadingIndicator(),
///   error: (error, _) => Text('Error: $error'),
/// );
/// ```
@riverpod
Stream<ConnectivityStatus> connectivityStream(Ref ref) {
  final connectivity = ref.watch(connectivityProvider);

  return connectivity.onConnectivityChanged.map((result) {
    // Handle the List<ConnectivityResult> from connectivity_plus
    if (result.contains(ConnectivityResult.wifi)) {
      return ConnectivityStatus.wifi;
    } else if (result.contains(ConnectivityResult.mobile)) {
      return ConnectivityStatus.mobile;
    } else {
      return ConnectivityStatus.offline;
    }
  });
}

/// Provider that checks current connectivity status once
/// This is useful for one-time checks without listening to changes
///
/// Usage:
/// ```dart
/// final status = await ref.read(currentConnectivityProvider.future);
/// if (status == ConnectivityStatus.offline) {
///   showOfflineDialog();
/// }
/// ```
@riverpod
Future<ConnectivityStatus> currentConnectivity(Ref ref) async {
  final connectivity = ref.watch(connectivityProvider);
  final result = await connectivity.checkConnectivity();

  // Handle the List<ConnectivityResult>
  if (result.contains(ConnectivityResult.wifi)) {
    return ConnectivityStatus.wifi;
  } else if (result.contains(ConnectivityResult.mobile)) {
    return ConnectivityStatus.mobile;
  } else {
    return ConnectivityStatus.offline;
  }
}

/// Provider that returns whether the device is currently online
/// Convenient boolean check for connectivity
///
/// Usage:
/// ```dart
/// final isOnlineAsync = ref.watch(isOnlineProvider);
/// isOnlineAsync.when(
///   data: (isOnline) => isOnline ? Text('Online') : Text('Offline'),
///   loading: () => const CustomLoadingIndicator(),
///   error: (error, _) => Text('Error: $error'),
/// );
/// ```
@riverpod
Stream<bool> isOnline(Ref ref) {
  // Get the connectivity stream and map it to a boolean
  final connectivity = ref.watch(connectivityProvider);

  return connectivity.onConnectivityChanged.map((result) {
    // Online if connected to WiFi or mobile
    return result.contains(ConnectivityResult.wifi) ||
        result.contains(ConnectivityResult.mobile);
  });
}

/// Example of using .select() for optimization
/// Only rebuilds when the online status changes, not on WiFi<->Mobile switches
///
/// Usage:
/// ```dart
/// // This only rebuilds when going online/offline
/// final isOnline = ref.watch(
///   connectivityStreamProvider.select((async) =>
///     async.value != ConnectivityStatus.offline
///   ),
/// );
/// ```
