import 'dart:async';
import 'package:meta/meta.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';

import 'package:{{ name }}/repository/TokenRepository.dart';
import 'package:{{ name }}/repository/AuthenticationRepository.dart';

import 'package:{{ name }}/models/User.dart';

part 'AuthenticationEvent.dart';
part 'AuthenticationState.dart';

class AuthenticationBloc extends Bloc<AuthenticationEvent, AuthenticationState> {
  final TokenRepository tokenRepository;
  final AuthenticationRepository authenticationRepository;

  AuthenticationBloc({
    @required this.tokenRepository,
    @required this.authenticationRepository,
  })  : assert(tokenRepository != null),
        assert(authenticationRepository != null);

  @override
  AuthenticationState get initialState => AuthenticationUninitialized();

  @override
  Stream<AuthenticationState> mapEventToState(AuthenticationEvent event) async* {
    if (event is AppLoaded) {
      final bool hasToken = await tokenRepository.hasToken();

      if (hasToken) {
        final token = await authenticationRepository.refresh();
        await tokenRepository.setToken(token.accessToken);
        final currentUser = await authenticationRepository.getUser();
        yield AuthenticationAuthenticated(user: currentUser);
      } else {
        yield AuthenticationUnauthenticated();
      }
    }

    if (event is UserLoggedIn) {
      yield AuthenticationLoading();
      await tokenRepository.setToken(event.token);
      final currentUser = await authenticationRepository.getUser();
      yield AuthenticationAuthenticated(user: currentUser);
    }

    if (event is UserLoggedOut) {
      yield AuthenticationLoading();

      try {
        await authenticationRepository.logout();
        await tokenRepository.deleteToken();

        yield AuthenticationUnauthenticated();
      } catch (error) {
        yield AuthenticationFailure(error: error.toString());
      }
    }
  }

}