import 'dart:async';

import 'package:aitrainer_app/bloc/account/account_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/user_repository.dart';
import 'package:aitrainer_app/util/common.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';

part 'login_event.dart';
part 'login_state.dart';

class LoginBloc extends Bloc<LoginEvent, LoginState> with Trans {
  final AccountBloc accountBloc;
  final UserRepository userRepository;
  final CustomerRepository customerRepository = CustomerRepository();
  final BuildContext context;
  final bool isRegistration;
  bool dataPolicyAllowed = false;
  bool emailSubscription = false;
  bool obscure = true;

  LoginBloc({required this.accountBloc, required this.userRepository, required this.context, required this.isRegistration})
      : super(LoginInitial());

  @override
  Stream<LoginState> mapEventToState(
    LoginEvent event,
  ) async* {
    try {
      if (event is LoginEmailChange) {
        yield LoginLoading();
        final String email = event.email;
        userRepository.setEmail(email);
        yield LoginReady();
      } else if (event is LoginPasswordChange) {
        yield LoginLoading();
        final String password = event.password;
        userRepository.setPassword(password);
        yield LoginReady();
      } else if (event is LoginSubmit) {
        yield LoginLoading();
        await userRepository.getUser();
        accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
        Track().track(TrackingEvent.login, eventValue: "email");
        Cache().setLoginType(LoginType.email);
        yield LoginSuccess();
      } else if (event is LoginFB) {
        yield LoginLoading();
        Cache().setLoginType(LoginType.fb);
        await userRepository.getUserByFB();
        accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
        Track().track(TrackingEvent.login, eventValue: "FB");
        yield LoginSuccess();
      } else if (event is LoginGoogle) {
        yield LoginLoading();
        Cache().setLoginType(LoginType.google);
        await userRepository.getUserByGoogle();
        accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
        Track().track(TrackingEvent.login, eventValue: "Google");
        yield LoginSuccess();
      } else if (event is LoginApple) {
        yield LoginLoading();
        Cache().setLoginType(LoginType.apple);
        await userRepository.getUserByApple();
        accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
        Track().track(TrackingEvent.login, eventValue: "Apple");
        yield LoginSuccess();
      } else if (event is RegistrationSubmit) {
        yield LoginLoading();
        if (!this.dataPolicyAllowed) {
          throw Exception("Please accept our data policy");
        }
        final String? validationError = validate();
        if (validationError != null) {
          yield LoginError(message: validationError);
        } else {
          await userRepository.addUser();
          accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
          customerRepository.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
          await saveCustomer();
          Track().track(TrackingEvent.registration, eventValue: "email");
          Cache().setLoginType(LoginType.email);
          yield LoginSuccess();
        }
      } else if (event is RegistrationFB) {
        yield LoginLoading();
        if (!this.dataPolicyAllowed) {
          throw Exception("Please accept our data policy");
        }
        Cache().setLoginType(LoginType.fb);
        await userRepository.addUserFB();
        accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
        customerRepository.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
        await saveCustomer();
        Track().track(TrackingEvent.registration, eventValue: "FB");
        yield LoginSuccess();
      } else if (event is RegistrationGoogle) {
        yield LoginLoading();
        if (!this.dataPolicyAllowed) {
          throw Exception("Please accept our data policy");
        }
        Cache().setLoginType(LoginType.google);
        await userRepository.addUserGoogle();
        accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
        customerRepository.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
        await saveCustomer();
        Track().track(TrackingEvent.registration, eventValue: "Google");
        yield LoginSuccess();
      } else if (event is RegistrationApple) {
        yield LoginLoading();
        if (!this.dataPolicyAllowed) {
          throw Exception("Please accept our data policy");
        }
        Cache().setLoginType(LoginType.apple);
        await userRepository.addUserApple();
        accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
        customerRepository.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
        await saveCustomer();
        Track().track(TrackingEvent.registration, eventValue: "Apple");

        yield LoginSuccess();
      } else if (event is DataProtectionClicked) {
        yield LoginLoading();
        this.dataPolicyAllowed = !dataPolicyAllowed;
        yield LoginReady();
      } else if (event is EmailSubscriptionClicked) {
        yield LoginLoading();
        this.emailSubscription = !emailSubscription;
        yield LoginReady();
      } else if (event is LoginPasswordChangeObscure) {
        yield LoginLoading();
        this.obscure = !this.obscure;
        yield LoginReady();
      } else if (event is LoginSkip) {
        yield LoginLoading();
        Track().track(TrackingEvent.login_skip);
        Cache().startPage = "home";
        yield LoginSkipped();
      }
    } on Exception catch (e) {
      yield LoginError(message: e.toString());
    }
  }

  Future<void> saveCustomer() async {
    customerRepository.customer = Cache().userLoggedIn!;
    customerRepository.customer!.dataPolicyAllowed = 1;
    await customerRepository.saveCustomer();
  }

  String? emailValidation(String? email) {
    String? message = Common.emailValidation(email);
    return message;
  }

  String? passwordValidation(String? value) {
    String? message = Common.passwordValidation(value);
    if (message != null) {
      message = t(message);
    }
    return message;
  }

  String? validate() {
    String? error;

    error = emailValidation(userRepository.user.email);
    if (error != null) {
      return error;
    }

    error = passwordValidation(userRepository.user.password);
    if (error != null) {
      return error;
    }

    return error;
  }
}
