import 'package:bloc/bloc.dart';
import '../session/session_bloc.dart';
import '../session/session_event.dart';
import '../session/session_state.dart';
import 'auth_event.dart';
import 'auth_state.dart';
import '../../services/api_client.dart';
import '../../models/api_error.dart';

class AuthBloc extends Bloc<AuthEvent, AuthState> {
  final ApiClient apiClient;
  final SessionBloc sessionBloc;

  AuthBloc({required this.apiClient, required this.sessionBloc})
    : super(AuthInitial()) {
    on<SignupStarted>(_onSignupStarted);
    on<RegistrationChallengeRequested>(_onRegistrationChallengeRequested);
    on<RegistrationResponseSubmitted>(_onRegistrationResponseSubmitted);
    on<LoginRequested>(_onLoginRequested);
    on<PasswordLoginRequested>(_onPasswordLoginRequested);
    on<AuthenticationChallengeRequested>(_onAuthenticationChallengeRequested);
    on<AuthenticationResponseSubmitted>(_onAuthenticationResponseSubmitted);
    on<LogoutRequested>(_onLogoutRequested);
    on<CheckAuthRequested>(_onCheckAuthRequested);
  }

  Future<void> _onSignupStarted(
    SignupStarted event,
    Emitter<AuthState> emit,
  ) async {
    emit(AuthLoading(message: 'Creating account...'));
    try {
      final response = await apiClient.post(
        '/auth/signup',
        data: {
          'username': event.username,
          'email': event.email,
          'displayName': event.displayName,
          'password': event.password ?? '',
        },
        fromJson: (data) => data,
      );

      final userId = response['userId'];
      emit(
        SignupInProgress(
          username: event.username,
          email: event.email,
          displayName: event.displayName,
        ),
      );

      // Trigger registration challenge request
      add(RegistrationChallengeRequested(userId: userId));
    } catch (e) {
      final errorMessage = _extractErrorMessage(e);
      emit(AuthFailure(errorMessage));
    }
  }

  Future<void> _onRegistrationChallengeRequested(
    RegistrationChallengeRequested event,
    Emitter<AuthState> emit,
  ) async {
    emit(AuthLoading(message: 'Getting registration challenge...'));
    try {
      final response = await apiClient.post(
        '/auth/registration-challenge',
        data: {'userId': event.userId},
        fromJson: (data) => data,
      );

      emit(
        RegistrationChallengeReceived(
          userId: event.userId,
          challenge: response['challenge'],
          rpName: response['rp']['name'],
          rpId: response['rp']['id'],
        ),
      );
    } catch (e) {
      final errorMessage = _extractErrorMessage(e);
      emit(AuthFailure(errorMessage));
    }
  }

  Future<void> _onRegistrationResponseSubmitted(
    RegistrationResponseSubmitted event,
    Emitter<AuthState> emit,
  ) async {
    emit(AuthLoading(message: 'Verifying registration...'));
    try {
      final response = await apiClient.post(
        '/auth/registration-verify',
        data: {
          'userId': event.userId,
          'challenge': event.challenge,
          'credentialId': event.credentialId,
          'publicKey': event.publicKey,
          'clientDataJSON': event.clientDataJSON,
          'attestationObject': event.attestationObject,
        },
        fromJson: (data) => data,
      );

      final token = response['token'];
      final user = response['user'];

      sessionBloc.add(SessionStarted(token));

      emit(
        AuthAuthenticated(
          token: token,
          userId: user['id'],
          username: user['username'],
          email: user['email'],
        ),
      );
    } catch (e) {
      final errorMessage = _extractErrorMessage(e);
      emit(AuthFailure(errorMessage));
    }
  }

  Future<void> _onLoginRequested(
    LoginRequested event,
    Emitter<AuthState> emit,
  ) async {
    emit(AuthLoading(message: 'Requesting authentication challenge...'));
    try {
      add(AuthenticationChallengeRequested(username: event.username));
    } catch (e) {
      final errorMessage = _extractErrorMessage(e);
      emit(AuthFailure(errorMessage));
    }
  }

  Future<void> _onAuthenticationChallengeRequested(
    AuthenticationChallengeRequested event,
    Emitter<AuthState> emit,
  ) async {
    try {
      final response = await apiClient.post(
        '/auth/authentication-challenge',
        data: {'username': event.username},
        fromJson: (data) => data,
      );

      final credentialIds =
          (response['allowCredentials'] as List?)
              ?.map((id) => id.toString())
              .toList() ??
          [];

      emit(
        AuthenticationChallengeReceived(
          challenge: response['challenge'],
          credentialIds: credentialIds,
        ),
      );
    } catch (e) {
      final errorMessage = _extractErrorMessage(e);
      emit(AuthFailure(errorMessage));
    }
  }

  Future<void> _onAuthenticationResponseSubmitted(
    AuthenticationResponseSubmitted event,
    Emitter<AuthState> emit,
  ) async {
    emit(AuthLoading(message: 'Verifying authentication...'));
    try {
      final response = await apiClient.post(
        '/auth/authentication-verify',
        data: {
          'username': event.username,
          'challenge': event.challenge,
          'credentialId': event.credentialId,
          'authenticatorData': event.authenticatorData,
          'clientDataJSON': event.clientDataJSON,
          'signature': event.signature,
        },
        fromJson: (data) => data,
      );

      final token = response['token'];
      final user = response['user'];

      sessionBloc.add(SessionStarted(token));

      emit(
        AuthAuthenticated(
          token: token,
          userId: user['id'],
          username: user['username'],
          email: user['email'],
        ),
      );
    } catch (e) {
      final errorMessage = _extractErrorMessage(e);
      emit(AuthFailure(errorMessage));
    }
  }

  Future<void> _onLogoutRequested(
    LogoutRequested event,
    Emitter<AuthState> emit,
  ) async {
    emit(AuthLoading(message: 'Logging out...'));
    await Future.delayed(const Duration(milliseconds: 500));
    sessionBloc.add(SessionExpired());
    emit(AuthUnauthenticated());
  }

  Future<void> _onPasswordLoginRequested(
    PasswordLoginRequested event,
    Emitter<AuthState> emit,
  ) async {
    emit(AuthLoading(message: 'Authenticating...'));
    try {
      final response = await apiClient.post(
        '/auth/password-login',
        data: {'username': event.username, 'password': event.password},
        fromJson: (data) => data,
      );

      final token = response['token'];
      final user = response['user'];

      sessionBloc.add(SessionStarted(token));
      emit(
        AuthAuthenticated(
          token: token,
          userId: user['id'],
          username: user['username'],
          email: user['email'],
        ),
      );
    } catch (e) {
      final errorMessage = _extractErrorMessage(e);
      emit(AuthFailure(errorMessage));
    }
  }

  String _extractErrorMessage(dynamic error) {
    if (error is ApiError) {
      return error.message;
    }
    return error.toString();
  }

  Future<void> _onCheckAuthRequested(
    CheckAuthRequested event,
    Emitter<AuthState> emit,
  ) async {
    // Check if session is active from persistent storage
    final sessionState = sessionBloc.state;

    if (sessionState is SessionActive) {
      // Session already active - emit authenticated state with minimal info
      // The full user info will be fetched when needed
      emit(
        AuthAuthenticated(
          token: sessionState.token,
          userId: '',
          username: '',
          email: '',
        ),
      );
    } else {
      emit(AuthUnauthenticated());
    }
  }
}
