import 'package:flutter_modular/flutter_modular.dart';
import 'package:bloc/bloc.dart';
import 'package:krow_domain/krow_domain.dart';
import '../../domain/arguments/sign_in_with_phone_arguments.dart';
import '../../domain/arguments/verify_otp_arguments.dart';
import '../../domain/usecases/sign_in_with_phone_usecase.dart';
import '../../domain/usecases/verify_otp_usecase.dart';
import 'auth_event.dart';
import 'auth_state.dart';

/// BLoC responsible for handling authentication logic.
class AuthBloc extends Bloc<AuthEvent, AuthState> implements Disposable {
  /// The use case for signing in with a phone number.
  final SignInWithPhoneUseCase _signInUseCase;

  /// The use case for verifying an OTP.
  final VerifyOtpUseCase _verifyOtpUseCase;

  /// Creates an [AuthBloc].
  AuthBloc({
    required SignInWithPhoneUseCase signInUseCase,
    required VerifyOtpUseCase verifyOtpUseCase,
  }) : _signInUseCase = signInUseCase,
       _verifyOtpUseCase = verifyOtpUseCase,
       super(const AuthState()) {
    on<AuthSignInRequested>(_onSignInRequested);
    on<AuthOtpSubmitted>(_onOtpSubmitted);
    on<AuthErrorCleared>(_onErrorCleared);
    on<AuthOtpUpdated>(_onOtpUpdated);
    on<AuthPhoneUpdated>(_onPhoneUpdated);
  }

  /// Clears any authentication error from the state.
  void _onErrorCleared(AuthErrorCleared event, Emitter<AuthState> emit) {
    emit(state.copyWith(status: AuthStatus.codeSent, errorMessage: null));
  }

  /// Updates the internal OTP state without triggering a submission.
  void _onOtpUpdated(AuthOtpUpdated event, Emitter<AuthState> emit) {
    emit(
      state.copyWith(
        otp: event.otp,
        status: AuthStatus.codeSent,
        errorMessage: null,
      ),
    );
  }

  /// Updates the internal phone number state without triggering a submission.
  void _onPhoneUpdated(AuthPhoneUpdated event, Emitter<AuthState> emit) {
    emit(state.copyWith(phoneNumber: event.phoneNumber, errorMessage: null));
  }

  /// Handles the sign-in request, initiating the phone authentication process.
  Future<void> _onSignInRequested(
    AuthSignInRequested event,
    Emitter<AuthState> emit,
  ) async {
    emit(
      state.copyWith(
        status: AuthStatus.loading,
        mode: event.mode,
        phoneNumber: event.phoneNumber,
      ),
    );
    try {
      final String? verificationId = await _signInUseCase(
        SignInWithPhoneArguments(
          phoneNumber: event.phoneNumber ?? state.phoneNumber,
        ),
      );
      emit(
        state.copyWith(
          status: AuthStatus.codeSent,
          verificationId: verificationId,
        ),
      );
    } catch (e) {
      emit(
        state.copyWith(status: AuthStatus.error, errorMessage: e.toString()),
      );
    }
  }

  /// Handles OTP submission and verification.
  Future<void> _onOtpSubmitted(
    AuthOtpSubmitted event,
    Emitter<AuthState> emit,
  ) async {
    emit(state.copyWith(status: AuthStatus.loading));
    try {
      final User? user = await _verifyOtpUseCase(
        VerifyOtpArguments(
          verificationId: event.verificationId,
          smsCode: event.smsCode,
          mode: event.mode,
        ),
      );
      emit(state.copyWith(status: AuthStatus.authenticated, user: user));
    } catch (e) {
      emit(
        state.copyWith(status: AuthStatus.error, errorMessage: e.toString()),
      );
    }
  }

  /// Disposes the BLoC resources.
  @override
  void dispose() {
    close();
  }
}
