import 'package:cloud_firestore/cloud_firestore.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../core/firebase/firebase_providers.dart'; /// Anmeldung, Registrierung und der Haushalts-Bootstrap. class AuthRepository { AuthRepository(this._auth, this._firestore); final FirebaseAuth _auth; final FirebaseFirestore _firestore; Future signIn({required String email, required String password}) async { await _auth.signInWithEmailAndPassword(email: email, password: password); } /// Registrierung: legt den Auth-Nutzer an und danach Profil + Haushalt. Future signUp({required String email, required String password}) async { final credential = await _auth.createUserWithEmailAndPassword( email: email, password: password, ); await ensureHouseholdBootstrap(credential.user!.uid, email); } /// Anmeldung mit Apple. Nativer Dialog auf iOS, Web-Flow (über den /// Firebase-Auth-Handler) auf Android — beides über den eingebauten /// [AppleAuthProvider], daher ohne Zusatz-Paket. /// /// Der Haushalts-Bootstrap hängt bewusst NICHT mehr hier dran: sobald /// signInWithProvider zurückkehrt, feuert authStateChanges und der Router /// leitet in die App weiter — ein danach geworfener Bootstrap-Fehler wäre /// auf dem Login-Screen unsichtbar und ließe den Nutzer ohne Haushalt /// zurück. Stattdessen übernimmt der reaktive householdBootstrapProvider. Future signInWithApple() async { final provider = AppleAuthProvider() ..addScope('email') ..addScope('name'); await _auth.signInWithProvider(provider); } Future? _bootstrapInFlight; /// Legt Profil-Dokument und einen eigenen Haushalt an, falls für [uid] /// noch keins existiert. Idempotent und gegen parallele Aufrufe geschützt /// (Registrierung und reaktiver Bootstrap können sich überlappen) — /// ein bestehender Haushalt wird nie überschrieben. Future ensureHouseholdBootstrap(String uid, String? email) { return _bootstrapInFlight ??= _bootstrapHouseholdIfNeeded(uid, email).whenComplete(() { _bootstrapInFlight = null; }); } /// [email] kann bei „E-Mail verbergen“ die Apple-Relay-Adresse sein. Future _bootstrapHouseholdIfNeeded(String uid, String? email) async { final userRef = _firestore.collection('users').doc(uid); if ((await userRef.get()).exists) return; final safeEmail = email ?? ''; final householdRef = _firestore.collection('households').doc(); final batch = _firestore.batch(); batch.set(householdRef, { 'name': 'Mein Haushalt', 'ownerUid': uid, 'memberUids': [uid], 'members': { uid: { 'role': 'member', 'email': safeEmail, 'joinedAt': FieldValue.serverTimestamp(), }, }, 'createdAt': FieldValue.serverTimestamp(), }); batch.set(userRef, { 'email': safeEmail, 'householdId': householdRef.id, 'createdAt': FieldValue.serverTimestamp(), }); await batch.commit(); } Future signOut() => _auth.signOut(); } final authRepositoryProvider = Provider((ref) { return AuthRepository( ref.watch(firebaseAuthProvider), ref.watch(firestoreProvider), ); });