import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:get_it/get_it.dart';
import 'package:http/http.dart' as http;
import 'package:shared_preferences/shared_preferences.dart';

import '../../features/auth/data/datasources/auth_local_datasource.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/presentation/viewmodels/auth_viewmodel.dart';
import '../../features/settings/data/settings_local_datasource.dart';
import '../../features/settings/domain/enums/app_mode.dart';
import '../../features/settings/presentation/viewmodels/settings_viewmodel.dart';
import '../../features/tasks/data/datasources/task_local_datasource.dart';
import '../../features/tasks/data/datasources/task_remote_datasource.dart';
import '../../features/tasks/data/repositories/local_task_repository_impl.dart';
import '../../features/tasks/data/repositories/task_repository_impl.dart';
import '../../features/tasks/domain/repositories/task_repository.dart';
import '../../features/tasks/presentation/viewmodels/daily_tasks_viewmodel.dart';
import '../../features/tasks/presentation/viewmodels/task_form_viewmodel.dart';
import '../database/app_database.dart';
import '../logging/app_logger.dart';
import '../network/authenticated_client.dart';

final getIt = GetIt.instance;

Future<void> init() async {
  // External
  final sharedPreferences = await SharedPreferences.getInstance();
  getIt.registerSingleton<SharedPreferences>(sharedPreferences);

  const flutterSecureStorage = FlutterSecureStorage(
    aOptions: AndroidOptions(encryptedSharedPreferences: true),
    iOptions: IOSOptions(accessibility: KeychainAccessibility.first_unlock),
  );
  getIt.registerSingleton<FlutterSecureStorage>(flutterSecureStorage);

  // Logger
  getIt.registerSingleton<AppLogger>(AppLogger());

  // Auth Data sources
  getIt.registerLazySingleton<AuthLocalDataSource>(
    () => AuthLocalDataSourceImpl(storage: getIt()),
  );
  getIt.registerLazySingleton<AuthRemoteDataSource>(
    () => AuthRemoteDataSourceImpl(logger: getIt()),
  );

  // Auth Repository
  getIt.registerLazySingleton<AuthRepository>(
    () => AuthRepositoryImpl(
      remoteDataSource: getIt(),
      localDataSource: getIt(),
      logger: getIt(),
    ),
  );

  // Auth ViewModel (singleton for global state)
  getIt.registerSingleton<AuthViewModel>(
    AuthViewModel(repository: getIt(), logger: getIt()),
  );

  // Authenticated HTTP Client
  getIt.registerLazySingleton<http.Client>(
    () => AuthenticatedClient(
      localDataSource: getIt(),
      authRepository: getIt(),
    ),
  );

  // Settings Data Source (must be registered before SettingsViewModel)
  getIt.registerLazySingleton<SettingsLocalDataSource>(
    () => SettingsLocalDataSourceImpl(sharedPreferences: getIt()),
  );

  // Database (for local mode)
  getIt.registerLazySingleton<AppDatabase>(() => AppDatabase());

  // Task Data sources
  getIt.registerLazySingleton<TaskRemoteDataSource>(
    () => TaskRemoteDataSourceImpl(
      logger: getIt(),
      client: getIt<http.Client>(),
    ),
  );
  getIt.registerLazySingleton<TaskLocalDataSource>(
    () => TaskLocalDataSourceImpl(database: getIt()),
  );

  // Task Repository (mode-aware)
  // We use a factory that checks the current app mode
  getIt.registerFactory<TaskRepository>(() {
    final settingsDataSource = getIt<SettingsLocalDataSource>();
    final appMode = settingsDataSource.getAppMode();

    if (appMode == AppMode.local) {
      return LocalTaskRepositoryImpl(
        localDataSource: getIt(),
        logger: getIt(),
      );
    } else {
      return TaskRepositoryImpl(
        remoteDataSource: getIt(),
        logger: getIt(),
      );
    }
  });

  // ViewModels
  getIt.registerFactory<DailyTasksViewModel>(
    () => DailyTasksViewModel(repository: getIt(), logger: getIt()),
  );
  getIt.registerFactory<TaskFormViewModel>(
    () => TaskFormViewModel(repository: getIt(), logger: getIt()),
  );
  getIt.registerLazySingleton<SettingsViewModel>(
    () => SettingsViewModel(dataSource: getIt(), logger: getIt()),
  );
}
