import 'dart:io';
import 'package:cargocalculaterapp/features/auth/presentation/bloc/auth/auth_bloc.dart';
import 'package:cargocalculaterapp/features/auth/presentation/bloc/sign_up/sign_up_bloc.dart';
import 'package:cargocalculaterapp/features/calculator/presentation/bloc/calculator_bloc.dart';
import 'package:cargocalculaterapp/features/home/domain/usecase/order_single_usecase.dart';
import 'package:cargocalculaterapp/features/home/presentation/bloc/home_bloc.dart';
import 'package:cargocalculaterapp/features/home/presentation/bloc/notification/notification_bloc.dart';
import 'package:cargocalculaterapp/features/profile/domain/repository/profile_repository.dart';
import 'package:cargocalculaterapp/features/profile/presentation/bloc/profile_bloc.dart';
import 'package:cargocalculaterapp/router/app_routes.dart';
import 'package:cargocalculaterapp/router/name_routes.dart';
import 'package:dio/dio.dart';
import 'package:dio_retry_plus/dio_retry_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:get_it/get_it.dart';
import 'package:hive/hive.dart';
import 'package:internet_connection_checker_plus/internet_connection_checker_plus.dart';
import 'package:path_provider/path_provider.dart';
import 'core/app_bloc/app_bloc.dart';
import 'core/local_source/local_source.dart';
import 'core/platform/network_info.dart';
import 'features/auth/data/data_source/remote/auth_remote_data_source.dart';
import 'features/auth/data/data_source/remote/auth_remote_data_source_impl.dart';
import 'features/auth/data/repository/auth_repository_impl.dart';
import 'features/auth/domain/repository/auth_repository.dart';
import 'features/auth/domain/usecases/fcm_add_usecase.dart';
import 'features/auth/domain/usecases/login_usecase.dart';
import 'features/auth/domain/usecases/sign_up_usecase.dart';
import 'features/auth/domain/usecases/verify_phone_usecase.dart';
import 'features/auth/presentation/bloc/auth_confirm/auth_confirm_bloc.dart';
import 'features/calculator/data/data_source/calculator_remote_data_source.dart';
import 'features/calculator/data/data_source/calculator_remote_data_source_impl.dart';
import 'features/calculator/data/repository/calculator_repository_impl.dart';
import 'features/calculator/domain/repository/calculator_repository.dart';
import 'features/calculator/domain/usecase/calculate_price_usecase.dart';
import 'features/calculator/domain/usecase/create_lead_usecase.dart';
import 'features/calculator/presentation/bloc/calculator_info/calculator_info_bloc.dart';
import 'features/home/data/data_source/remote/home_remote_data_source.dart';
import 'features/home/data/data_source/remote/home_remote_data_source_impl.dart';
import 'features/home/data/repository/home_repository_impl.dart';
import 'features/home/domain/repository/home_repository.dart';
import 'features/home/domain/usecase/banners_usecase.dart';
import 'features/home/domain/usecase/comment_usecase.dart';
import 'features/home/domain/usecase/notification_read_usecase.dart';
import 'features/home/domain/usecase/notification_usecase.dart';
import 'features/home/domain/usecase/orders_list_usecase.dart';
import 'features/home/presentation/bloc/comment/comment_bloc.dart';
import 'features/home/presentation/bloc/order_single/order_single_bloc.dart';
import 'features/main/presentation/bloc/main_bloc.dart';
import 'features/profile/data/data_source/local/profile_local_data_source.dart';
import 'features/profile/data/data_source/local/profile_local_data_source_impl.dart';
import 'features/profile/data/data_source/remote/profile_remote_data_source.dart';
import 'features/profile/data/data_source/remote/profile_remote_data_source_impl.dart';
import 'features/profile/data/repository/profile_repository_impl.dart';
import 'features/profile/domain/usecase/delete_profile_usecase.dart';
import 'features/profile/domain/usecase/profile_update_usecase.dart';
import 'features/profile/domain/usecase/profile_usecase.dart';

final sl = GetIt.instance;
late Box<dynamic> _box;

Future<void> init() async {
  //External
  await initHive();
  sl.registerSingleton<LocalSource>(LocalSource(_box));
  sl.registerLazySingleton(
    () => Dio()
      ..interceptors.addAll([
        LogInterceptor(

          request: kDebugMode,
          responseBody: kDebugMode,
          error: kDebugMode,
          requestBody: kDebugMode,
        ),
        // chuck.dioInterceptor,
      ]),
  );
  sl.registerLazySingleton(() => InternetConnection());
  //Core
  sl.registerLazySingleton<NetworkInfo>(() => NetworkInfoImpl(sl()));
  sl.registerSingleton<AppBloc>(AppBloc());
  sl<Dio>().interceptors.add(
    RetryInterceptor(
      dio: sl<Dio>(),
      retryDelays: const [Duration(seconds: 3), Duration(seconds: 2)],
      toNoInternetPageNavigator: () async {
        // Navigator.pushNamed(
        //   rootNavigatorKey.currentContext!,
        //   Routes.noConnection,"email": "umarforsiy@gmail.com",
        // );
      },
      accessTokenGetter: () => "Bearer ${sl<LocalSource>().getAccessToken()}",
      refreshTokenFunction: () async {
        final language = sl<LocalSource>().getLocale();
        await sl<LocalSource>().clear().then((value) {
          sl<LocalSource>().setLocale(language);
          sl<LocalSource>().setIsFirstEnter(false);
          if (rootNavigatorKey.currentContext?.mounted ?? false) {
            Navigator.pushNamedAndRemoveUntil(
              rootNavigatorKey.currentContext!,
              Routes.auth,
              (route) => false,
            );
          }
        });
      },
      forbiddenFunction: () async {},
      logPrint: (message) {
        if (kDebugMode) {
          print(message);
        }
      },
    ),
  );

  // Features
  _mainFeature();
  _auth();
  _profile();
  _home();
  _calculator();
}

void _auth() {
  sl.registerFactory(() => AuthBloc(sl()));
  sl.registerFactory(() => SignUpBloc(sl()));
  sl.registerFactory(() => AuthConfirmBloc(sl(), sl(), sl(), sl()));

  /// UseCases
  sl.registerLazySingleton<LoginUseCase>(() => LoginUseCase(sl()));
  sl.registerLazySingleton<SignUpUseCase>(() => SignUpUseCase(sl()));
  sl.registerLazySingleton<VerifyPhoneUseCase>(() => VerifyPhoneUseCase(sl()));
  sl.registerLazySingleton<FcmAddUseCase>(() => FcmAddUseCase(sl()));

  ///Repositories
  sl.registerLazySingleton<AuthRepository>(() => AuthRepositoryImpl(sl()));

  /// Data and Network
  sl.registerLazySingleton<AuthRemoteDataSource>(
    () => AuthRemoteDataSourceImpl(sl()),
  );
}

void _mainFeature() {
  sl.registerFactory(() => MainBloc());
}

void _profile() {
  sl.registerFactory(() => ProfileBloc(sl(), sl(), sl()));

  /// UseCases
  sl.registerLazySingleton<ProfileUseCase>(() => ProfileUseCase(sl()));
  sl.registerLazySingleton<DeleteProfileUseCase>(
    () => DeleteProfileUseCase(sl()),
  );
  sl.registerLazySingleton<ProfileUpdateUseCase>(
    () => ProfileUpdateUseCase(sl()),
  );

  ///Repositories
  sl.registerLazySingleton<ProfileRepository>(
    () => ProfileRepositoryImpl(sl(), sl()),
  );

  /// Data and Network
  sl.registerLazySingleton<ProfileRemoteDataSource>(
    () => ProfileRemoteDataSourceImpl(sl()),
  );
  sl.registerLazySingleton<ProfileLocalDataSource>(
    () => ProfileLocalDataSourceImpl(_box),
  );
}

void _home() {
  sl.registerFactory(() => HomeBloc(sl(), sl()));
  sl.registerFactory(() => OrderSingleBloc(sl()));
  sl.registerFactory(() => CommentBloc(sl()));
  sl.registerFactory(() => NotificationBloc(sl(), sl()));

  /// UseCases
  sl.registerLazySingleton<OrdersListUseCase>(() => OrdersListUseCase(sl()));
  sl.registerLazySingleton<OrderSingleUseCase>(() => OrderSingleUseCase(sl()));
  sl.registerLazySingleton<CommentUseCase>(() => CommentUseCase(sl()));
  sl.registerLazySingleton<NotificationUseCase>(
    () => NotificationUseCase(sl()),
  );
  sl.registerLazySingleton<NotificationReadUseCase>(
    () => NotificationReadUseCase(sl()),
  );
  sl.registerLazySingleton<BannersUseCase>(() => BannersUseCase(sl()));

  ///Repositories
  sl.registerLazySingleton<HomeRepository>(() => HomeRepositoryImpl(sl()));

  /// Data and Network
  sl.registerLazySingleton<HomeRemoteDataSource>(
    () => HomeRemoteDataSourceImpl(sl()),
  );
}

void _calculator() {
  sl.registerFactory(() => CalculatorBloc(sl()));
  sl.registerFactory(() => CalculatorInfoBloc(sl()));

  /// UseCases
  sl.registerLazySingleton<CalculatePriceUseCase>(
    () => CalculatePriceUseCase(sl()),
  );
  sl.registerLazySingleton<CreateLeadUseCase>(() => CreateLeadUseCase(sl()));

  ///Repositories
  sl.registerLazySingleton<CalculatorRepository>(
    () => CalculatorRepositoryImpl(sl()),
  );

  /// Data and Network
  sl.registerLazySingleton<CalculatorRemoteDataSource>(
    () => CalculatorRemoteDataSourceImpl(sl()),
  );
}

Future<void> initHive({bool isTest = false}) async {
  const boxName = 'cargocalculator';

  final Directory directory = await getApplicationDocumentsDirectory();
  Hive.init(directory.path);

  _box = await Hive.openBox<dynamic>(boxName);
}

class LogBlocObserver extends BlocObserver {
  @override
  void onChange(BlocBase bloc, Change change) {
    super.onChange(bloc, change);
    if (kDebugMode) {
      print(change);
    }
  }

  @override
  void onClose(BlocBase bloc) {
    super.onClose(bloc);
    if (kDebugMode) {
      print("$bloc closed");
    }
  }

  @override
  void onCreate(BlocBase bloc) {
    super.onCreate(bloc);
    if (kDebugMode) {
      print("$bloc created");
    }
  }

  @override
  void onEvent(Bloc bloc, Object? event) {
    super.onEvent(bloc, event);
    if (kDebugMode) {
      print('${bloc.runtimeType} $event');
    }
  }

  @override
  void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
    super.onError(bloc, error, stackTrace);
    if (kDebugMode) {
      print('${bloc.runtimeType} $error');
    }
  }

  @override
  void onTransition(Bloc bloc, Transition transition) {
    super.onTransition(bloc, transition);
    if (kDebugMode) {
      print(transition.toString());
    }
  }
}
