import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../data/models/user_model.dart' as app; import '../../../data/repositories/user_repository.dart'; import '../../../bootstrap/supabase_client.dart'; import '../../../core/errors/failure.dart'; import '../../../core/utils/unit_conversion_utils.dart'; final profileControllerProvider = StateNotifierProvider((ref) { final client = supabaseClient; final repository = client != null ? UserRepository(client) : null; return ProfileController(repository); }); class ProfileController extends StateNotifier { final UserRepository? _repository; ProfileController(this._repository) : super(const ProfileState.initial()); Future loadProfile(String userId) async { if (_repository == null) { state = const ProfileState.error('Profile is unavailable while offline.'); return; } state = const ProfileState.loading(); try { final user = await _repository!.getProfile(userId); state = ProfileState.loaded(user); } on Failure catch (failure) { state = ProfileState.error(failure.message); } catch (e) { state = ProfileState.error(e.toString()); } } Future updateUsername(String userId, String username) async { if (_repository == null) { state = const ProfileState.error('Profile is unavailable while offline.'); return; } state = const ProfileState.loading(); try { final isAvailable = await _repository!.isUsernameAvailable(username); if (!isAvailable) { state = const ProfileState.error('Username is already taken'); return; } final updatedUser = await _repository!.updateProfile( userId: userId, username: username, ); state = ProfileState.loaded(updatedUser); } on Failure catch (failure) { state = ProfileState.error(failure.message); } catch (e) { state = ProfileState.error(e.toString()); } } Future updateBio(String userId, String bio) async { if (_repository == null) { state = const ProfileState.error('Profile is unavailable while offline.'); return; } state = const ProfileState.loading(); try { final updatedUser = await _repository!.updateProfile( userId: userId, bio: bio, ); state = ProfileState.loaded(updatedUser); } on Failure catch (failure) { state = ProfileState.error(failure.message); } catch (e) { state = ProfileState.error(e.toString()); } } Future updateAvatarUrl(String userId, String avatarUrl) async { if (_repository == null) { state = const ProfileState.error('Profile is unavailable while offline.'); return; } state = const ProfileState.loading(); try { final updatedUser = await _repository!.updateProfile( userId: userId, avatarUrl: avatarUrl, ); state = ProfileState.loaded(updatedUser); } on Failure catch (failure) { state = ProfileState.error(failure.message); } catch (e) { state = ProfileState.error(e.toString()); } } Future toggleProfileVisibility(String userId) async { if (_repository == null) { state = const ProfileState.error('Profile is unavailable while offline.'); return; } final currentState = state; if (currentState.user == null) return; state = const ProfileState.loading(); try { final updatedUser = await _repository!.updateProfile( userId: userId, isPublicProfile: !currentState.user!.isPublicProfile, ); state = ProfileState.loaded(updatedUser); } on Failure catch (failure) { state = ProfileState.error(failure.message); } catch (e) { state = ProfileState.error(e.toString()); } } Future completeProfileSetup({ required String userId, required String username, String? bio, String? avatarUrl, String? twitterHandle, String? instagramHandle, String? tiktokHandle, String? websiteUrl, Gender? gender, DateTime? birthDate, double? heightCm, double? weightKg, HeightUnit heightUnit = HeightUnit.metric, WeightUnit weightUnit = WeightUnit.metric, }) async { if (_repository == null) { state = const ProfileState.error('Profile is unavailable while offline.'); return; } state = const ProfileState.loading(); try { final isAvailable = await _repository!.isUsernameAvailable(username); if (!isAvailable) { state = const ProfileState.error('Username is already taken'); return; } final updatedUser = await _repository!.updateProfile( userId: userId, username: username, bio: bio, avatarUrl: avatarUrl, twitterHandle: twitterHandle, instagramHandle: instagramHandle, tiktokHandle: tiktokHandle, websiteUrl: websiteUrl, gender: gender, birthDate: birthDate, heightCm: heightCm, weightKg: weightKg, heightUnit: heightUnit, weightUnit: weightUnit, ); state = ProfileState.loaded(updatedUser); } on Failure catch (failure) { state = ProfileState.error(failure.message); } catch (e) { state = ProfileState.error(e.toString()); } } Future isProfileSetupComplete(String userId) async { if (_repository == null) { return false; } try { final user = await _repository!.getProfile(userId); return user.username.isNotEmpty; } catch (e) { return false; } } } class ProfileState { final bool isLoading; final app.User? user; final String? errorMessage; const ProfileState({ this.isLoading = false, this.user, this.errorMessage, }); const ProfileState.initial() : isLoading = false, user = null, errorMessage = null; const ProfileState.loading() : isLoading = true, user = null, errorMessage = null; const ProfileState.loaded(this.user) : isLoading = false, errorMessage = null; const ProfileState.error(this.errorMessage) : isLoading = false, user = null; } typedef ProfileStateLoaded = ProfileState;