/// Address Provider
///
/// Riverpod providers for address management.
library;

import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:worker/core/network/dio_client.dart';
import 'package:worker/features/account/data/datasources/address_remote_datasource.dart';
import 'package:worker/features/account/data/repositories/address_repository_impl.dart';
import 'package:worker/features/account/domain/entities/address.dart';
import 'package:worker/features/account/domain/repositories/address_repository.dart';

part 'address_provider.g.dart';

// ============================================================================
// DATASOURCE PROVIDER
// ============================================================================

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

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

/// Provides instance of AddressRepository
@riverpod
Future<AddressRepository> addressRepository(Ref ref) async {
  final remoteDataSource =
      await ref.watch(addressRemoteDataSourceProvider.future);

  return AddressRepositoryImpl(
    remoteDataSource: remoteDataSource,
  );
}

// ============================================================================
// ADDRESSES LIST PROVIDER
// ============================================================================

/// Manages list of addresses with online-only approach
///
/// This is the MAIN provider for the addresses feature.
/// Returns list of Address entities from the API.
///
/// Online-only: Always fetches from API, no offline caching.
/// Uses keepAlive to prevent unnecessary reloads.
/// Provides refresh() method for pull-to-refresh functionality.
@Riverpod(keepAlive: true)
class Addresses extends _$Addresses {
  late AddressRepository _repository;

  @override
  Future<List<Address>> build() async {
    _repository = await ref.read(addressRepositoryProvider.future);
    return await _loadAddresses();
  }

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

  /// Load addresses from repository
  ///
  /// Online-only: Fetches from API
  Future<List<Address>> _loadAddresses() async {
    try {
      final addresses = await _repository.getAddresses();
      _debugPrint('Loaded ${addresses.length} addresses');
      return addresses;
    } catch (e) {
      _debugPrint('Error loading addresses: $e');
      rethrow;
    }
  }

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

  /// Create new address
  ///
  /// Calls API to create address, then refreshes the list.
  Future<void> createAddress(Address address) async {
    try {
      _debugPrint('Creating address: ${address.addressTitle}');

      await _repository.createAddress(address);

      // Refresh the list after successful creation
      await refresh();

      _debugPrint('Successfully created address');
    } catch (e) {
      _debugPrint('Error creating address: $e');
      rethrow;
    }
  }

  /// Update existing address
  ///
  /// Calls API to update address, then refreshes the list.
  Future<void> updateAddress(Address address) async {
    try {
      _debugPrint('Updating address: ${address.name}');

      await _repository.updateAddress(address);

      // Refresh the list after successful update
      await refresh();

      _debugPrint('Successfully updated address');
    } catch (e) {
      _debugPrint('Error updating address: $e');
      rethrow;
    }
  }

  /// Delete address
  ///
  /// Calls API to delete address, then refreshes the list.
  Future<void> deleteAddress(String name) async {
    try {
      _debugPrint('Deleting address: $name');

      await _repository.deleteAddress(name);

      // Refresh the list after successful deletion
      await refresh();

      _debugPrint('Successfully deleted address');
    } catch (e) {
      _debugPrint('Error deleting address: $e');
      rethrow;
    }
  }

  /// Set address as default
  ///
  /// Calls API to set address as default, then refreshes the list.
  Future<void> setDefaultAddress(String name) async {
    try {
      _debugPrint('Setting default address: $name');

      await _repository.setDefaultAddress(name);

      // Refresh the list after successful update
      await refresh();

      _debugPrint('Successfully set default address');
    } catch (e) {
      _debugPrint('Error setting default address: $e');
      rethrow;
    }
  }

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

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

/// Get the default address
///
/// Derived from the addresses list.
/// Returns the address marked as default, or null if none.
@riverpod
Address? defaultAddress(Ref ref) {
  final addressesAsync = ref.watch(addressesProvider);

  return addressesAsync.when(
    data: (addresses) {
      try {
        return addresses.firstWhere((addr) => addr.isDefault);
      } catch (e) {
        return null;
      }
    },
    loading: () => null,
    error: (_, __) => null,
  );
}

/// Get address count
///
/// Derived from the addresses list.
/// Returns the number of addresses.
@riverpod
int addressCount(Ref ref) {
  final addressesAsync = ref.watch(addressesProvider);

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

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

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