import 'dart:async';

import 'package:fcs/data/services/services.dart';
import 'package:fcs/domain/entities/auth_result.dart';
import 'package:fcs/domain/entities/setting.dart';
import 'package:fcs/domain/entities/user.dart';
import 'package:fcs/helpers/network_connectivity.dart';
import 'package:fcs/helpers/shared_pref.dart';
import 'package:fcs/pages/main/model/base_model.dart';
import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart';
import 'package:package_info/package_info.dart';

class MainModel extends ChangeNotifier {
  final log = Logger('MainModel');
  List<BaseModel> models = [];

  String messagingToken;
  User user;
  PackageInfo packageInfo;

  set setMessaginToken(token) {
    this.messagingToken = token;
    uploadMsgToken();
  }

  Setting setting;

  bool isLoaded = false;
  bool isOnline = false;
  bool isFirstLaunch = false;

  MainModel() {
    NetworkConnectivity.instance.statusStream.listen((data) {
      bool _isOnline = data["isOnline"];
      if (_isOnline && !this.isOnline) {
        _init();
      }
      this.isOnline = _isOnline;
      notifyListeners();
    });
  }

  bool faqEditable() {
    return this.user != null && this.user.hasSupport();
  }

  bool rateEditable() {
    return this.user != null && this.user.hasSupport();
  }

  bool paymentMethodsEditable() {
    return this.user != null && this.user.hasSupport();
  }

  bool termEditable() {
    return this.user != null && this.user.hasSupport();
  }

  bool contactEditable() {
    return this.user != null && this.user.hasSupport();
  }

  bool isLogin() {
    return this.user != null;
  }

  bool isCustomer() {
    return user != null && user.isCustomer();
  }

  bool isSysAdmin() {
    return this.user != null && this.user.hasSysAdmin();
  }

  bool isAdmin() {
    return this.user != null && this.user.hasAdmin();
  }

  // userListener should never be closed
  StreamSubscription<User> userListener;
  _init() async {
    await _listenSetting();
    this.isFirstLaunch = await SharedPref.isFirstLaunch();
    this.isFirstLaunch = this.isFirstLaunch ?? true;
    this.packageInfo = await PackageInfo.fromPlatform();

    if (userListener != null) userListener.cancel();
    userListener =
        Services.instance.authService.getUserStream().listen((_user) {
      if (_user != null) {
        models.forEach((m) => m.initUser(_user));
        // call diffPrivileges if privilege changed or first time login
        if (this.user == null || _user.diffPrivileges(this.user)) {
          models.forEach((m) => m.privilegeChanged());
        }
        if (this.user == null) {
          uploadMsgToken();
        }
      } else {
        if (this.user != null) {
          models.forEach((m) => m.logout());
        }
      }
      this.user = _user;
      isLoaded = true;
      notifyListeners();
    });
  }

  void addModel(BaseModel model) {
    models.add(model);
  }

  Future<void> _listenSetting() async {
    try {
      Services.instance.authService.getSetting().listen((event) {
        this.setting = event;
        models.forEach((m) => m.initSetting(setting));
        notifyListeners();
      });
    } finally {}
  }

  bool isSupport() {
    if (packageInfo == null || setting == null) return false;
    return int.parse(packageInfo.buildNumber) >= setting.supportBuildNum;
  }

  Future<AuthResult> sendSms(String phoneNumber) {
    return Services.instance.authService.sendSmsCodeToPhoneNumber(phoneNumber);
  }

  Future<AuthResult> signin(String smsCode) async {
    AuthResult authResult =
        await Services.instance.authService.signInWithSmsCode(smsCode);
    return authResult;
  }

  Future<void> uploadMsgToken() {
    if (messagingToken == null || user == null) return null;
    return Services.instance.userService.uploadMsgToken(messagingToken);
  }

  Future<void> removeMsgToken() {
    if (messagingToken == null || user == null) return null;
    return Services.instance.userService.removeMsgToken(messagingToken);
  }

  Future<void> signout() async {
    try {
      await removeMsgToken();
    } catch (e) {}
    await Services.instance.authService.signout();
    models.forEach((m) => m.logout());
  }

  Future<bool> hasInvite() async {
    return Services.instance.authService.hasInvite();
  }

  Future<void> signup(String userName) async {
    await Services.instance.authService.signup(userName);
  }

  Future<void> joinInvite(String userName) async {
    await Services.instance.authService.joinInvite(userName);
    notifyListeners();
  }

  Future<void> updateProfileName(String newUserName) async {
    await Services.instance.authService.updateProfileName(newUserName);
    notifyListeners();
  }

  Future<void> updatePreferredCurrency(String currency) async {
    await Services.instance.authService.updatePreferredCurrency(currency);
    notifyListeners();
  }
}
