import 'dart:async';

import 'package:aitrainer_app/bloc/account/account_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/customer.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/repository/mautic_repository.dart';
import 'package:aitrainer_app/repository/split_test_respository.dart';
import 'package:aitrainer_app/repository/training_plan_repository.dart';
import 'package:aitrainer_app/repository/user_repository.dart';
import 'package:aitrainer_app/util/app_language.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;
  late CustomerRepository? customerRepository;
  final SplitTestRepository splitTestRepository = SplitTestRepository();
  final BuildContext context;
  final bool isRegistration;
  bool dataPolicyAllowed = false;
  bool emailSubscription = false;
  bool obscure = true;

  Color testColor = Colors.green[800]!;
  bool emailCheckbox = true;

  LoginBloc({required this.accountBloc, required this.userRepository, required this.context, required this.isRegistration, this.customerRepository})
      : super(LoginInitial()) {
    this._init();
    on<LoginEmailChange>(_onEmailChange);
    on<LoginPasswordChange>(_onPasswordChange);
    on<LoginSubmit>(_onSubmit);
    on<LoginFB>(_onLoginFB);
    on<LoginGoogle>(_onLoginGoogle);
    on<LoginApple>(_onLoginApple);
    on<RegistrationSubmit>(_onRegistrationSubmit);
    on<RegistrationFB>(_onRegistrationFB);
    on<RegistrationGoogle>(_onRegistrationGoogle);
    on<RegistrationApple>(_onRegistrationApple);
    on<DataProtectionClicked>(_onDataProtectionClicked);
    on<EmailSubscriptionClicked>(_onEmailSubscriptionClicked);
    on<LoginPasswordChangeObscure>(_onPasswordChangeObscure);
    on<LoginSkip>(_onLoginSkip);
  }

  void _init() {
    String colorString = splitTestRepository.getSplitTestValue("registration_skip");
    if (colorString == "red") {
      testColor = Colors.red[800]!;
    }
    String emailCheckboxString = splitTestRepository.getSplitTestValue("email_checkbox");
    if (emailCheckboxString == "0") {
      emailCheckbox = false;
    }
    if (customerRepository == null) {
      customerRepository = CustomerRepository();
    }
  }

  void _onEmailChange(LoginEmailChange event, Emitter<LoginState> emit) {
    emit(LoginLoading());
    final String email = event.email;
    userRepository.setEmail(email);
    emit(LoginReady());
  }

  void _onPasswordChange(LoginPasswordChange event, Emitter<LoginState> emit) {
    emit(LoginLoading());
    final String password = event.password;
    userRepository.setPassword(password);
    emit(LoginReady());
  }

  void _onSubmit(LoginSubmit event, Emitter<LoginState> emit) async {
    emit(LoginLoading());
    await userRepository.getUser();
    accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
    Track().track(TrackingEvent.login, eventValue: "email");
    Cache().setLoginType(LoginType.email);

    emit(LoginReady());
  }

  void _onLoginFB(LoginFB event, Emitter<LoginState> emit) async {
    emit(LoginLoading());
    Cache().setLoginType(LoginType.fb);
    await userRepository.getUserByFB();
    accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
    Track().track(TrackingEvent.login, eventValue: "FB");
    emit(LoginReady());
  }

  void _onLoginGoogle(LoginGoogle event, Emitter<LoginState> emit) async {
    emit(LoginLoading());
    Cache().setLoginType(LoginType.google);
    await userRepository.getUserByGoogle();
    accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
    Track().track(TrackingEvent.login, eventValue: "Google");

    emit(LoginSuccess());
  }

  void _onLoginApple(LoginApple event, Emitter<LoginState> emit) async {
    emit(LoginLoading());
    Cache().setLoginType(LoginType.apple);
    await userRepository.getUserByApple();
    accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
    Track().track(TrackingEvent.login, eventValue: "Apple");
    emit(LoginSuccess());
  }

  void _onRegistrationSubmit(RegistrationSubmit event, Emitter<LoginState> emit) async {
    emit(LoginLoading());
    final String? validationError = this.validate();
    if (validationError != null) {
      emit(LoginError(message: validationError));
    } else {
      await userRepository.addUser();
      accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
      customerRepository!.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
      await afterRegistration("email");
      Cache().setLoginType(LoginType.email);
    }
    emit(LoginSuccess());
  }

  void _onRegistrationFB(RegistrationFB event, Emitter<LoginState> emit) async {
    emit(LoginLoading());
    Cache().setLoginType(LoginType.fb);
    await userRepository.addUserFB();
    accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
    customerRepository!.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
    await afterRegistration("FB");
    emit(LoginSuccess());
  }

  void _onRegistrationGoogle(RegistrationGoogle event, Emitter<LoginState> emit) async {
    emit(LoginLoading());
    Cache().setLoginType(LoginType.google);
    await userRepository.addUserGoogle();
    accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
    customerRepository!.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
    await afterRegistration("Google");
    emit(LoginSuccess());
  }

  void _onRegistrationApple(RegistrationApple event, Emitter<LoginState> emit) async {
    emit(LoginLoading());
    Cache().setLoginType(LoginType.apple);
    await userRepository.addUserApple();
    accountBloc.add(AccountLogInFinished(customer: Cache().userLoggedIn!));
    customerRepository!.customer!.emailSubscription = emailSubscription == true ? 1 : 0;
    await afterRegistration("Apple");
    emit(LoginSuccess());
  }

  void _onDataProtectionClicked(DataProtectionClicked event, Emitter<LoginState> emit) async {
    emit(LoginLoading());
    this.dataPolicyAllowed = !dataPolicyAllowed;
    emit(LoginReady());
  }

  void _onEmailSubscriptionClicked(EmailSubscriptionClicked event, Emitter<LoginState> emit) async {
    emit(LoginLoading());
    this.emailSubscription = !emailSubscription;
    emit(LoginReady());
  }

  void _onPasswordChangeObscure(LoginPasswordChangeObscure event, Emitter<LoginState> emit) async {
    emit(LoginLoading());
    this.obscure = !this.obscure;
    emit(LoginReady());
  }

  void _onLoginSkip(LoginSkip event, Emitter<LoginState> emit) async {
    emit(LoginLoading());
    Track().track(TrackingEvent.login_skip);
    Cache().startPage = "home";
    emit(LoginSkipped());
  }

  Future<void> afterRegistration(String event) async {
    Customer tempCustomer = customerRepository!.customer!;
    customerRepository!.customer = Cache().userLoggedIn!;
    customerRepository!.customer!.fitnessLevel = tempCustomer.fitnessLevel;
    customerRepository!.customer!.goal = tempCustomer.goal;
    customerRepository!.customer!.sex = tempCustomer.sex;
    customerRepository!.customer!.dataPolicyAllowed = 1;
    customerRepository!.customer!.emailSubscription = 1;
    customerRepository!.customer!.syncedDate = DateTime.now();
    customerRepository!.customer!.lang = AppLanguage().appLocal.languageCode;
    customerRepository!.setCustomerProperty("Weight", tempCustomer.getProperty("Weight"));
    customerRepository!.setCustomerProperty("Height", tempCustomer.getProperty("Height"));
    await customerRepository!.saveCustomer();
    MauticRepository mauticRepository = MauticRepository(customerRepository: customerRepository!);
    await mauticRepository.sendMauticSubscription();
    TrainingPlanRepository trainingPlanRepository = TrainingPlanRepository();
    trainingPlanRepository.generateTrainingPlan();
    Track().track(TrackingEvent.registration, eventValue: event);
  }

  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;
  }
}
