import 'dart:async';
import 'dart:developer';

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:krow/core/application/di/injectable.dart';
import 'package:krow/core/data/enums/state_status.dart';
import 'package:krow/core/sevices/auth_state_service/auth_service.dart';
import 'package:krow/features/profile/email_verification/data/email_verification_service.dart';

part 'email_verification_event.dart';

part 'email_verification_state.dart';

/// This BLoC is currently unfinished.
/// We faced an issue with the Firebase email verification process. As a
/// security-sensitive action, it requires recent user authentication (seems
/// like around 5-10 minutes), so we have to prompt the user to re-login. Only
/// after that can the verification email be sent.
/// But upon receiving the email and confirming it, another issue arises: the
/// current auth token becomes invalid, and the user is silently signed out from
/// Firebase. On mobile, it can be solved by integrating a deep-link into the
/// verification email, which will allow us to re-authenticate the user with
/// an email link credential in the background.
/// However, there is a possibility that the user might verify his email on a
/// desktop (or any other device), so the link won't be received. In this case,
/// we need to prompt the user to re-authenticate yet again. This will probably
/// be a bad user experience.
class EmailVerificationBloc
    extends Bloc<EmailVerificationEvent, EmailVerificationState> {
  EmailVerificationBloc() : super(const EmailVerificationState()) {
    on<SetVerifiedData>((event, emit) async {
      emit(state.copyWith(
        email: event.verifiedEmail,
        userPhone: event.userPhone,
      ));

      add(const SendVerificationEmail());
    });

    on<SendVerificationEmail>((event, emit) async {
      try {
        await _verificationService.sendVerificationEmail(email: state.email);

        emailCheckTimer?.cancel();
        emailCheckTimer = Timer.periodic(
          const Duration(seconds: 3),
              (_) => add(const CheckEmailStatus()),
        );
      } catch (except) {
        log(
          'Error in EmailVerificationBloc. On SetVerifiedEmail event',
          error: except,
        );

        if (except is FirebaseAuthException) {
          emit(
            state.copyWith(
              reAuthRequirement:
              _verificationService.isReAuthenticationRequired(except.code),
            ),
          );
        }
      } finally {
        emit(state.copyWith(reAuthRequirement: ReAuthRequirement.none));
      }
    });

    on<CheckEmailStatus>((event, emit) async {
      bool isEmailVerified = false;
      try {
        isEmailVerified = await _verificationService.isUserEmailVerified(
          newEmail: state.email,
        );
      } catch (except) {
        log(
          'Error in EmailVerificationBloc. On CheckEmailStatus event',
          error: except,
        );
        if (except is FirebaseAuthException) {
          emit(
            state.copyWith(
              reAuthRequirement:
                  _verificationService.isReAuthenticationRequired(except.code),
            ),
          );
        }
      }

      emit(
        state.copyWith(
          status: isEmailVerified ? StateStatus.success : StateStatus.idle,
        ),
      );

      if (state.status == StateStatus.success) emailCheckTimer?.cancel();
    });

    on<ResendVerificationEmail>((event, emit) {
      emit(state.copyWith(reAuthRequirement: ReAuthRequirement.none));

      add(const SendVerificationEmail());
    });

    on<IncomingVerificationLink>((event, emit) async {
      try {
        await getIt<AuthService>().signInWithEmailLink(
          link: event.verificationLink,
        );

        emit(state.copyWith(status: StateStatus.success));
      } catch (except) {
        log(
          'Error in EmailVerificationBloc. On IncomingVerificationLink event',
          error: except,
        );
      }

      if (state.status == StateStatus.success) emailCheckTimer?.cancel();
    });
  }

  final _verificationService = getIt<EmailVerificationService>();
  Timer? emailCheckTimer;

  @override
  Future<void> close() {
    emailCheckTimer?.cancel();
    return super.close();
  }
}
