/// Location Provider
///
/// Riverpod providers for cities and wards management.
library;

import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:worker/core/database/hive_service.dart';
import 'package:worker/core/network/dio_client.dart';
import 'package:worker/features/account/data/datasources/location_local_datasource.dart';
import 'package:worker/features/account/data/datasources/location_remote_datasource.dart';
import 'package:worker/features/account/data/repositories/location_repository_impl.dart';
import 'package:worker/features/account/domain/entities/city.dart';
import 'package:worker/features/account/domain/entities/ward.dart';
import 'package:worker/features/account/domain/repositories/location_repository.dart';

part 'location_provider.g.dart';

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

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

/// Provides instance of LocationLocalDataSource
@riverpod
LocationLocalDataSource locationLocalDataSource(Ref ref) {
  final hiveService = HiveService();
  return LocationLocalDataSource(hiveService);
}

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

/// Provides instance of LocationRepository
@riverpod
Future<LocationRepository> locationRepository(Ref ref) async {
  final remoteDataSource = await ref.watch(locationRemoteDataSourceProvider.future);
  final localDataSource = ref.watch(locationLocalDataSourceProvider);

  return LocationRepositoryImpl(
    remoteDataSource: remoteDataSource,
    localDataSource: localDataSource,
  );
}

// ============================================================================
// CITIES PROVIDER
// ============================================================================

/// Manages list of cities with offline-first approach
///
/// This is the MAIN provider for cities.
/// Returns list of City entities (cached → API).
@Riverpod(keepAlive: true)
class Cities extends _$Cities {
  late LocationRepository _repository;

  @override
  Future<List<City>> build() async {
    _repository = await ref.read(locationRepositoryProvider.future);
    return await _loadCities();
  }

  /// Load cities (offline-first)
  Future<List<City>> _loadCities({bool forceRefresh = false}) async {
    try {
      final cities = await _repository.getCities(forceRefresh: forceRefresh);
      return cities;
    } catch (e) {
      rethrow;
    }
  }

  /// Refresh cities from API
  Future<void> refresh() async {
    state = const AsyncValue.loading();
    state = await AsyncValue.guard(() async {
      return await _loadCities(forceRefresh: true);
    });
  }
}

// ============================================================================
// WARDS PROVIDER (per city)
// ============================================================================

/// Manages list of wards for a specific city with offline-first approach
///
/// Uses .family modifier to create a provider per city code.
/// Returns list of Ward entities (cached → API).
@riverpod
Future<List<Ward>> wards(Ref ref, String cityCode) async {
  final repository = await ref.watch(locationRepositoryProvider.future);

  try {
    final wards = await repository.getWards(cityCode);
    return wards;
  } catch (e) {
    rethrow;
  }
}

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

/// Get city by code
@riverpod
City? cityByCode(Ref ref, String code) {
  final citiesAsync = ref.watch(citiesProvider);

  return citiesAsync.when(
    data: (cities) {
      try {
        return cities.firstWhere((city) => city.code == code);
      } catch (e) {
        return null;
      }
    },
    loading: () => null,
    error: (_, __) => null,
  );
}

/// Get cities as map (code → City) for easy lookup
@riverpod
Map<String, City> citiesMap(Ref ref) {
  final citiesAsync = ref.watch(citiesProvider);

  return citiesAsync.when(
    data: (cities) => {for (final city in cities) city.code: city},
    loading: () => {},
    error: (_, __) => {},
  );
}

/// Get wards as map (code → Ward) for a city
@riverpod
Map<String, Ward> wardsMap(Ref ref, String cityCode) {
  final wardsAsync = ref.watch(wardsProvider(cityCode));

  return wardsAsync.when(
    data: (wards) => {for (final ward in wards) ward.code: ward},
    loading: () => {},
    error: (_, __) => {},
  );
}
