import 'dart:developer' as developer;

import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:krow_domain/krow_domain.dart';

import '../../domain/arguments/sign_in_with_email_arguments.dart';
import '../../domain/arguments/sign_in_with_social_arguments.dart';
import '../../domain/arguments/sign_up_with_email_arguments.dart';
import '../../domain/usecases/sign_in_with_email_use_case.dart';
import '../../domain/usecases/sign_in_with_social_use_case.dart';
import '../../domain/usecases/sign_out_use_case.dart';
import '../../domain/usecases/sign_up_with_email_use_case.dart';
import 'client_auth_event.dart';
import 'client_auth_state.dart';

/// Business Logic Component for Client Authentication.
///
/// This BLoC manages the state transitions for the authentication flow in
/// the client application. It handles user inputs (events), interacts with
/// domain use cases, and emits corresponding [ClientAuthState]s.
///
/// Use this BLoC to handle:
/// * Email/Password Sign In
/// * Business Account Registration
/// * Social Authentication
/// * Session Termination
class ClientAuthBloc extends Bloc<ClientAuthEvent, ClientAuthState> {
  final SignInWithEmailUseCase _signInWithEmail;
  final SignUpWithEmailUseCase _signUpWithEmail;
  final SignInWithSocialUseCase _signInWithSocial;
  final SignOutUseCase _signOut;

  /// Initializes the BLoC with the required use cases and initial state.
  ClientAuthBloc({
    required SignInWithEmailUseCase signInWithEmail,
    required SignUpWithEmailUseCase signUpWithEmail,
    required SignInWithSocialUseCase signInWithSocial,
    required SignOutUseCase signOut,
  }) : _signInWithEmail = signInWithEmail,
       _signUpWithEmail = signUpWithEmail,
       _signInWithSocial = signInWithSocial,
       _signOut = signOut,
       super(const ClientAuthState()) {
    on<ClientSignInRequested>(_onSignInRequested);
    on<ClientSignUpRequested>(_onSignUpRequested);
    on<ClientSocialSignInRequested>(_onSocialSignInRequested);
    on<ClientSignOutRequested>(_onSignOutRequested);
  }

  /// Handles the [ClientSignInRequested] event.
  Future<void> _onSignInRequested(
    ClientSignInRequested event,
    Emitter<ClientAuthState> emit,
  ) async {
    emit(state.copyWith(status: ClientAuthStatus.loading));
    try {
      final User user = await _signInWithEmail(
        SignInWithEmailArguments(email: event.email, password: event.password),
      );
      emit(state.copyWith(status: ClientAuthStatus.authenticated, user: user));
    } on AppException catch (e) {
      developer.log('Error ${e.code}: ${e.technicalMessage}', name: 'ClientAuthBloc');
      emit(
        state.copyWith(
          status: ClientAuthStatus.error,
          errorMessage: e.messageKey,
        ),
      );
    } catch (e) {
      developer.log('Unexpected error: $e', name: 'ClientAuthBloc');
      emit(
        state.copyWith(
          status: ClientAuthStatus.error,
          errorMessage: 'errors.generic.unknown',
        ),
      );
    }
  }

  /// Handles the [ClientSignUpRequested] event.
  Future<void> _onSignUpRequested(
    ClientSignUpRequested event,
    Emitter<ClientAuthState> emit,
  ) async {
    emit(state.copyWith(status: ClientAuthStatus.loading));
    try {
      final User user = await _signUpWithEmail(
        SignUpWithEmailArguments(
          companyName: event.companyName,
          email: event.email,
          password: event.password,
        ),
      );
      emit(state.copyWith(status: ClientAuthStatus.authenticated, user: user));
    } on AppException catch (e) {
      developer.log('Error ${e.code}: ${e.technicalMessage}', name: 'ClientAuthBloc');
      emit(
        state.copyWith(
          status: ClientAuthStatus.error,
          errorMessage: e.messageKey,
        ),
      );
    } catch (e) {
      developer.log('Unexpected error: $e', name: 'ClientAuthBloc');
      emit(
        state.copyWith(
          status: ClientAuthStatus.error,
          errorMessage: 'errors.generic.unknown',
        ),
      );
    }
  }

  /// Handles the [ClientSocialSignInRequested] event.
  Future<void> _onSocialSignInRequested(
    ClientSocialSignInRequested event,
    Emitter<ClientAuthState> emit,
  ) async {
    emit(state.copyWith(status: ClientAuthStatus.loading));
    try {
      final User user = await _signInWithSocial(
        SignInWithSocialArguments(provider: event.provider),
      );
      emit(state.copyWith(status: ClientAuthStatus.authenticated, user: user));
    } on AppException catch (e) {
      developer.log('Error ${e.code}: ${e.technicalMessage}', name: 'ClientAuthBloc');
      emit(
        state.copyWith(
          status: ClientAuthStatus.error,
          errorMessage: e.messageKey,
        ),
      );
    } catch (e) {
      developer.log('Unexpected error: $e', name: 'ClientAuthBloc');
      emit(
        state.copyWith(
          status: ClientAuthStatus.error,
          errorMessage: 'errors.generic.unknown',
        ),
      );
    }
  }

  /// Handles the [ClientSignOutRequested] event.
  Future<void> _onSignOutRequested(
    ClientSignOutRequested event,
    Emitter<ClientAuthState> emit,
  ) async {
    emit(state.copyWith(status: ClientAuthStatus.loading));
    try {
      await _signOut();
      emit(state.copyWith(status: ClientAuthStatus.signedOut, user: null));
    } on AppException catch (e) {
      developer.log('Error ${e.code}: ${e.technicalMessage}', name: 'ClientAuthBloc');
      emit(
        state.copyWith(
          status: ClientAuthStatus.error,
          errorMessage: e.messageKey,
        ),
      );
    } catch (e) {
      developer.log('Unexpected error: $e', name: 'ClientAuthBloc');
      emit(
        state.copyWith(
          status: ClientAuthStatus.error,
          errorMessage: 'errors.generic.unknown',
        ),
      );
    }
  }
}
