import 'package:equatable/equatable.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:focusflow_shared/focusflow_shared.dart'; import '../../../../core/network/api_client.dart'; import '../../../../core/network/interceptors/auth_interceptor.dart'; import '../../../../main.dart'; // ── Events ───────────────────────────────────────────────────────── sealed class AuthEvent extends Equatable { const AuthEvent(); @override List get props => []; } class AuthLoginRequested extends AuthEvent { final String email; final String password; const AuthLoginRequested({required this.email, required this.password}); @override List get props => [email, password]; } class AuthSignupRequested extends AuthEvent { final String displayName; final String email; final String password; const AuthSignupRequested({ required this.displayName, required this.email, required this.password, }); @override List get props => [displayName, email, password]; } class AuthLogoutRequested extends AuthEvent { const AuthLogoutRequested(); } class AuthCheckRequested extends AuthEvent {} // ── States ───────────────────────────────────────────────────────── sealed class AuthState extends Equatable { const AuthState(); @override List get props => []; } class AuthInitial extends AuthState {} class AuthLoading extends AuthState {} class AuthAuthenticated extends AuthState { final User user; const AuthAuthenticated(this.user); @override List get props => [user]; } class AuthUnauthenticated extends AuthState {} class AuthError extends AuthState { final String message; const AuthError(this.message); @override List get props => [message]; } // ── BLoC ─────────────────────────────────────────────────────────── class AuthBloc extends Bloc { final ApiClient _api = getIt(); AuthBloc() : super(AuthInitial()) { on(_onCheck); on(_onLogin); on(_onSignup); on(_onLogout); } Future _onCheck(AuthCheckRequested event, Emitter emit) async { final hasToken = await AuthInterceptor.hasToken(); if (hasToken) { // In a production app we would validate the token and fetch the user profile. // For now we emit a placeholder user. emit(AuthAuthenticated( User( id: 'local', email: '', displayName: 'Friend', createdAt: DateTime.now(), ), )); } else { emit(AuthUnauthenticated()); } } Future _onLogin(AuthLoginRequested event, Emitter emit) async { emit(AuthLoading()); try { final response = await _api.login(event.email, event.password); if (response.status == 'success' && response.data != null) { final data = response.data!; await AuthInterceptor.saveTokens( accessToken: data['accessToken'] as String, refreshToken: data['refreshToken'] as String, ); final user = User.fromJson(data['user'] as Map); emit(AuthAuthenticated(user)); } else { emit(AuthError(response.error?.message ?? 'Login failed')); } } catch (e) { emit(AuthError('Something went wrong. Please try again.')); } } Future _onSignup(AuthSignupRequested event, Emitter emit) async { emit(AuthLoading()); try { final response = await _api.register(event.displayName, event.email, event.password); if (response.status == 'success' && response.data != null) { final data = response.data!; await AuthInterceptor.saveTokens( accessToken: data['accessToken'] as String, refreshToken: data['refreshToken'] as String, ); final user = User.fromJson(data['user'] as Map); emit(AuthAuthenticated(user)); } else { emit(AuthError(response.error?.message ?? 'Sign up failed')); } } catch (e) { emit(AuthError('Something went wrong. Please try again.')); } } Future _onLogout(AuthLogoutRequested event, Emitter emit) async { try { await _api.logout(); } catch (_) { // Best-effort server logout — clear local tokens regardless. } await AuthInterceptor.clearTokens(); emit(AuthUnauthenticated()); } }