import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:google_sign_in/google_sign_in.dart';

import '../../../../core/constants/api_constants.dart';
import '../../../../core/errors/failures.dart';
import '../../../../core/usecases/usecase.dart';
import '../../domain/entities/user_entity.dart';
import '../../domain/usecases/login_usecase.dart';
import '../../domain/usecases/register_usecase.dart';
import '../../domain/usecases/logout_usecase.dart';
import '../../domain/usecases/get_cached_user_usecase.dart';
import '../../domain/usecases/check_auth_status_usecase.dart';
import '../../domain/usecases/forgot_password_usecase.dart';
import '../../domain/usecases/login_with_google_usecase.dart';
import '../../../profile/data/services/profile_service.dart';

part 'auth_event.dart';
part 'auth_state.dart';

class AuthBloc extends Bloc<AuthEvent, AuthState> {
  final LoginUseCase loginUseCase;
  final LoginWithGoogleUseCase loginWithGoogleUseCase;
  final RegisterUseCase registerUseCase;
  final LogoutUseCase logoutUseCase;
  final GetCachedUserUseCase getCachedUserUseCase;
  final CheckAuthStatusUseCase checkAuthStatusUseCase;
  final ForgotPasswordUseCase forgotPasswordUseCase;
  final ProfileService profileService;
  final GoogleSignIn _googleSignIn;

  AuthBloc({
    required this.loginUseCase,
    required this.loginWithGoogleUseCase,
    required this.registerUseCase,
    required this.logoutUseCase,
    required this.getCachedUserUseCase,
    required this.checkAuthStatusUseCase,
    required this.forgotPasswordUseCase,
    required this.profileService,
  })  : _googleSignIn = GoogleSignIn.instance,
        super(AuthInitial()) {
    _googleSignIn.initialize(
      serverClientId: ApiConstants.googleServerClientId,
    );
    on<AuthCheckRequested>(_onAuthCheckRequested);
    on<AuthLoginRequested>(_onAuthLoginRequested);
    on<AuthGoogleLoginRequested>(_onAuthGoogleLoginRequested);
    on<AuthRegisterRequested>(_onAuthRegisterRequested);
    on<AuthLogoutRequested>(_onAuthLogoutRequested);
    on<AuthTwoFactorRequested>(_onAuthTwoFactorRequested);
    on<AuthUserUpdated>(_onAuthUserUpdated);
    on<AuthForgotPasswordRequested>(_onAuthForgotPasswordRequested);
  }

  Future<void> _onAuthCheckRequested(
    AuthCheckRequested event,
    Emitter<AuthState> emit,
  ) async {
    print('🔵 AUTH_BLOC: AuthCheckRequested event received');
    emit(AuthLoading());

    print('🔵 AUTH_BLOC: Calling checkAuthStatusUseCase');
    final result = await checkAuthStatusUseCase(NoParams());

    await result.fold(
      (failure) async {
        print('🔴 AUTH_BLOC: Auth check failed: ${failure.message}');
        emit(AuthUnauthenticated());
      },
      (isAuthenticated) async {
        print('🔵 AUTH_BLOC: Auth check result: $isAuthenticated');
        if (isAuthenticated) {
          print('🔵 AUTH_BLOC: User is authenticated, getting cached user');
          final userResult = await getCachedUserUseCase(NoParams());

          await userResult.fold(
            (failure) async {
              print(
                  '🔴 AUTH_BLOC: Failed to get cached user: ${failure.message}');
              emit(AuthUnauthenticated());
            },
            (user) async {
              if (user != null) {
                print('🟢 AUTH_BLOC: Cached user found: ${user.email}');
                emit(AuthAuthenticated(user: user));
              } else {
                print('🔴 AUTH_BLOC: No cached user found');
                emit(AuthUnauthenticated());
              }
            },
          );
        } else {
          print('🔵 AUTH_BLOC: User is not authenticated');
          emit(AuthUnauthenticated());
        }
      },
    );
  }

  Future<void> _onAuthLoginRequested(
    AuthLoginRequested event,
    Emitter<AuthState> emit,
  ) async {
    print(
        '🔵 AUTH_BLOC: AuthLoginRequested event received for email: ${event.email}');
    emit(AuthLoading());

    print('🔵 AUTH_BLOC: Calling loginUseCase');
    final result = await loginUseCase(
      LoginParams(
        email: event.email,
        password: event.password,
      ),
    );

    result.fold(
      (failure) {
        print(
            '🔴 AUTH_BLOC: Login failed with failure: ${failure.runtimeType} - ${failure.message}');
        if (failure is AuthFailure &&
            failure.message.contains('2FA required')) {
          print('🔴 AUTH_BLOC: 2FA required scenario detected in BLoC');
          // For now, just show error message. 2FA flow can be implemented later
          emit(AuthError(message: failure.message));
        } else {
          final errorMessage = _mapFailureToMessage(failure);
          print('🔴 AUTH_BLOC: Emitting AuthError with message: $errorMessage');
          emit(AuthError(message: errorMessage));
        }
      },
      (user) {
        print('🟢 AUTH_BLOC: Login successful for user: ${user.email}');
        emit(AuthAuthenticated(user: user));

        // Auto-fetch complete profile including author status
        print('🔵 AUTH_BLOC: Auto-fetching complete profile after login');
        profileService.autoFetchProfile();
      },
    );
  }

  Future<void> _onAuthGoogleLoginRequested(
    AuthGoogleLoginRequested event,
    Emitter<AuthState> emit,
  ) async {
    emit(AuthLoading());
    try {
      final googleUser = await _googleSignIn.authenticate();
      if (googleUser == null) {
        // User cancelled the login
        emit(AuthUnauthenticated());
        return;
      }

      final googleAuth = await googleUser.authentication;
      final idToken = googleAuth.idToken;

      if (idToken == null) {
        emit(const AuthError(message: 'Failed to get Google ID token.'));
        return;
      }

      final result =
          await loginWithGoogleUseCase(GoogleLoginParams(idToken: idToken));

      result.fold(
        (failure) => emit(AuthError(message: failure.message)),
        (user) => emit(AuthAuthenticated(user: user)),
      );
    } catch (error) {
      await _googleSignIn.signOut();
      emit(AuthError(message: error.toString()));
    }
  }

  Future<void> _onAuthRegisterRequested(
    AuthRegisterRequested event,
    Emitter<AuthState> emit,
  ) async {
    print(
        '🔵 AUTH_BLOC: AuthRegisterRequested event received for email: ${event.email}');
    print(
        '🔵 AUTH_BLOC: Registration details: ${event.firstName} ${event.lastName}');
    emit(AuthLoading());

    print('🔵 AUTH_BLOC: Calling registerUseCase');
    final result = await registerUseCase(
      RegisterParams(
        firstName: event.firstName,
        lastName: event.lastName,
        email: event.email,
        password: event.password,
        referralCode: event.referralCode,
      ),
    );

    result.fold(
      (failure) {
        print(
            '🔴 AUTH_BLOC: Registration failed with failure: ${failure.runtimeType} - ${failure.message}');
        final errorMessage = _mapFailureToMessage(failure);
        print('🔴 AUTH_BLOC: Emitting AuthError with message: $errorMessage');
        emit(AuthError(message: errorMessage));
      },
      (user) {
        print('🟢 AUTH_BLOC: Registration successful for user: ${user.email}');
        emit(AuthAuthenticated(user: user));

        // Auto-fetch complete profile including author status
        print(
            '🔵 AUTH_BLOC: Auto-fetching complete profile after registration');
        profileService.autoFetchProfile();
      },
    );
  }

  Future<void> _onAuthLogoutRequested(
    AuthLogoutRequested event,
    Emitter<AuthState> emit,
  ) async {
    print('🔵 AUTH_BLOC: AuthLogoutRequested event received');

    // Show loading state immediately
    emit(AuthLoading());

    try {
      print('🔵 AUTH_BLOC: Starting logout process');

      // Call logout use case (this handles API call and local cleanup)
      final result = await logoutUseCase(NoParams());

      result.fold(
        (failure) {
          print('🔴 AUTH_BLOC: Logout API failed: ${failure.message}');
          // Even if API call fails, we should still clear local data for security
          print('🟢 AUTH_BLOC: Local cleanup completed despite API failure');
        },
        (_) {
          print('🟢 AUTH_BLOC: Logout completed successfully');
        },
      );

      // Always emit AuthUnauthenticated regardless of API result for security
      print('🔵 AUTH_BLOC: Emitting AuthUnauthenticated (always)');
      emit(AuthUnauthenticated());
      print('✅ AUTH_BLOC: AuthUnauthenticated emitted successfully');
    } catch (e) {
      print('🔴 AUTH_BLOC: Unexpected error during logout: $e');
      // Always logout on any error for security
      print('🔵 AUTH_BLOC: Emitting AuthUnauthenticated (error path)');
      emit(AuthUnauthenticated());
      print('✅ AUTH_BLOC: AuthUnauthenticated emitted (error path)');
    }

    print('🟢 AUTH_BLOC: Logout process completed');
  }

  Future<void> _onAuthTwoFactorRequested(
    AuthTwoFactorRequested event,
    Emitter<AuthState> emit,
  ) async {
    emit(AuthLoading());

    // TODO: Implement 2FA verification use case
    // For now, we'll just emit an error
    emit(const AuthError(message: '2FA verification not implemented yet'));
  }

  Future<void> _onAuthUserUpdated(
    AuthUserUpdated event,
    Emitter<AuthState> emit,
  ) async {
    if (state is AuthAuthenticated) {
      emit(AuthAuthenticated(user: event.user));
    }
  }

  Future<void> _onAuthForgotPasswordRequested(
    AuthForgotPasswordRequested event,
    Emitter<AuthState> emit,
  ) async {
    print(
        '🔵 AUTH_BLOC: AuthForgotPasswordRequested event received for email: ${event.email}');
    emit(AuthLoading());

    print('🔵 AUTH_BLOC: Calling forgotPasswordUseCase');
    final result = await forgotPasswordUseCase(
      ForgotPasswordParams(email: event.email),
    );

    result.fold(
      (failure) {
        print(
            '🔴 AUTH_BLOC: Forgot password failed with failure: ${failure.runtimeType} - ${failure.message}');
        final errorMessage = _mapFailureToMessage(failure);
        print('🔴 AUTH_BLOC: Emitting AuthError with message: $errorMessage');
        emit(AuthError(message: errorMessage));
      },
      (_) {
        print(
            '🟢 AUTH_BLOC: Forgot password email sent successfully for: ${event.email}');
        emit(AuthForgotPasswordSent(email: event.email));
      },
    );
  }

  String _mapFailureToMessage(Failure failure) {
    switch (failure.runtimeType) {
      case NetworkFailure:
        return 'Network error. Please check your internet connection.';
      case ServerFailure:
        return failure.message.isNotEmpty
            ? failure.message
            : 'Server error occurred.';
      case AuthFailure:
        return failure.message.isNotEmpty
            ? failure.message
            : 'Authentication failed.';
      case ValidationFailure:
        return failure.message.isNotEmpty
            ? failure.message
            : 'Invalid input provided.';
      case UnauthorizedFailure:
        return 'Unauthorized access. Please login again.';
      case ForbiddenFailure:
        return 'Access denied.';
      case NotFoundFailure:
        return 'Resource not found.';
      case CacheFailure:
        return 'Local storage error occurred.';
      case TimeoutFailure:
        return 'Request timeout. Please try again.';
      case ConnectionFailure:
        return 'No internet connection.';
      default:
        return 'An unexpected error occurred.';
    }
  }
}
