import 'dart:async';
import 'dart:convert';
import 'dart:developer';
import 'dart:io';

import 'package:auto_route/auto_route.dart';
import 'package:dio/dio.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:mnemo_cards/di/locator.dart';
import 'package:mnemo_cards/main.dart';
import 'package:mnemo_cards/managers/repository/http_repository.dart';
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
import 'package:rxdart/rxdart.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:device_info_plus/device_info_plus.dart';

import '../domain/router/app_router.dart';
import '../domain/router/app_router.gr.dart';
import '../features/analytics/analytics.dart';
import 'user_state_holder.dart';

class UserManager {
  CompositeSubscription? _subscription;
  final HttpRepository _repository;
  GoogleSignIn _googleSignIn = GoogleSignIn(
    scopes: [
      'email',
      // 'https://www.googleapis.com/auth/contacts.readonly',
    ],
    // clientId: '01767851968-dvbvmte4m90dkqitp013s4nd5c0df1n8.apps.googleusercontent.com',
    // "701767851968-bud97rud1d9qtqju96addn31nhm0oofu.apps.googleusercontent.com",
  );

  late final SharedPreferences? _sharedPreferences;
  final UserStateHolder userStateHolder;

  UserManager(this._repository) : userStateHolder = UserStateHolder();

  bool get hasUser => userStateHolder.user != null;

  Future<void> login() async {
    if (await _googleSignIn.isSignedIn()) {
      await _googleSignIn.signOut();
    }
    final account = await _googleSignIn.signIn();
    await Future.delayed(Duration(milliseconds: 300));
  }

  Future<void> logout() async {
    if (await _googleSignIn.isSignedIn()) {
      await _googleSignIn.signOut();
    }
    Analytics.logout(userStateHolder.user);
    userStateHolder.clear();
  }

  Future<void> _createUser(
    String externalId,
    ExternalIdType idType,
    String? name,
  ) async {
    final (user, token) =
        await _repository.createOrGetUser(externalId, idType, name);
    _setAuthToken(token);
    userStateHolder.setUser(user);
  }

  void _setAuthToken(String authToken) async {
    _repository.setAuthToken(authToken);
    await _sharedPreferences!.setString('authToken', authToken);
  }

  void _clearAuthToken() async {
    await _sharedPreferences!.remove('authToken');
  }

  Future<UserDto?> _updateUser() async {
    String? authToken = _sharedPreferences!.getString('authToken');
    if (authToken != null) {
      _setAuthToken(authToken);
      try {
        final fetchedUser = await _repository.getUser();
        userStateHolder.setUser(fetchedUser!);
        return fetchedUser;
      } catch (e) {
        _clearAuthToken();
        AppRouter.openAuthOrProfile();
      }
    }
    // not creating empty user
    // if (Platform.isAndroid) {
    //   final deviceInfoPlugin = DeviceInfoPlugin();
    //   final deviceInfo = await deviceInfoPlugin.androidInfo;
    //   final id = deviceInfo.id;
    //   await _createUser(id, ExternalIdType.device);
    // }
    return null;
  }

  Future<void> init() async {
    _sharedPreferences = await SharedPreferences.getInstance();
    try {
      await _updateUser();
    } on Object catch (e, s) {
      log('User manager init error', error: e, stackTrace: s);
    }

    _subscription = CompositeSubscription()
      ..add(_googleSignIn.onCurrentUserChanged
          .startWith(_googleSignIn.currentUser)
          .distinct((p, n) => p?.id == n?.id)
          .listen((account) async {
        if (account != null) {
          final name = account.displayName;
          final token =
              await account.authentication.then((value) => value.idToken);
          Analytics.login(ExternalIdType.google);
          await _createUser(token!, ExternalIdType.google, name);
        }
      }))
      ..add(userStateHolder.asNullableStream
          .distinct((a, b) => a?.id == b?.id)
          .listen((user) async {
        try {
          if (user == null) {
            AppRouter.openAuthOrProfile();
          } else {
            try {
              AppRouter.closeAuthPage();
              await locator.previewPackPoller.poll();
              await locator.packManager.clearCache();
              await locator.packUpdater.updateAvailablePacks();
            } catch (err) {
              log(err.toString());
            }
          }
        } catch (e) {
          log(e.toString());
          _clearAuthToken();
          if (e is DioException) {
            if (e.response?.statusCode == 401) {
              appRouter.push(
                PageRouteInfo(ProfilePage.name),
              );
            }
          }
        }
      }));
  }

  Future<void> dispose() async {
    await _subscription?.cancel();
    _subscription = null;
  }
}

enum ExternalIdType { google, device }
