import 'dart:async';
import 'dart:convert';

import 'package:crypto/crypto.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/cupertino.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';

import 'accountModel.dart';

class AccountData {
  static const _usernameField = 'username';
  static const _passwordField = 'password';
  
  static final AccountData _instance = AccountData._construct();
  final Future<SharedPreferences> _storage = SharedPreferences.getInstance();
  Completer<void> _populated = Completer();

  factory AccountData() {
    return _instance;
  }

  AccountData._construct() {
    _updateFromStorage();
  }

  String? _username;
  String? _password;

  String getUsername() {
    if(_username == null) throw Exception('Username not initialized');
    return _username!;
  }

  String getPassword() {
    if(_password == null) throw Exception('Password not initialized');
    return _password!;
  }

  String getUserSecret() {
    return sha512.convert(utf8.encode('${AccountData().getUsername()}:${AccountData().getPassword()}')).toString();
  }

  Future<String> getDeviceId() async {
    return sha512.convert(utf8.encode('${getUserSecret()}@${await FirebaseMessaging.instance.getToken()}')).toString();
  }

  Future<void> setData(String username, String password) async {
    SharedPreferences storage = await _storage;

    storage.setString(_usernameField, username);
    storage.setString(_passwordField, password);
    await _updateFromStorage();
  }

  Future<void> removeData({BuildContext? context}) async {
    _populated = Completer();

    if(context != null) Provider.of<AccountModel>(context, listen: false).setState(AccountModelState.loggedOut);

    SharedPreferences storage = await _storage;
    await storage.remove(_usernameField);
    await storage.remove(_passwordField);
  }

  Future<void> _updateFromStorage() async {
    SharedPreferences storage = await _storage;
    //await storage.reload(); // This line was the cause of the first rejected google play upload :(
    if(storage.containsKey(_usernameField) && storage.containsKey(_passwordField)) {
      _username = storage.getString(_usernameField);
      _password = storage.getString(_passwordField);
    }
    if(!_populated.isCompleted) _populated.complete();
  }

  Future<bool> waitForPopulation() async {
    await _populated.future;
    return isPopulated();
  }

  bool isPopulated() {
    return _username != null && _password != null;
  }

  String buildHttpAuthString() {
    if(!isPopulated()) throw Exception('AccountData (e.g. username or password) is not initialized!');
    return '$_username:$_password';
  }
}