diff --git a/lib/services/cloud/firebase_account_sync_service.dart b/lib/services/cloud/firebase_account_sync_service.dart new file mode 100644 index 0000000..5279967 --- /dev/null +++ b/lib/services/cloud/firebase_account_sync_service.dart @@ -0,0 +1,72 @@ +import 'package:cloud_firestore/cloud_firestore.dart'; +import 'package:firebase_core/firebase_core.dart'; +import '../../database/database.dart'; +import '../auth/auth_service.dart'; +import 'cloud_models.dart'; + +/// Synchronizes account/profile and motorcycle metadata independently of the +/// ride upload pipeline. This keeps identity data small and queryable while +/// leaving high-frequency telemetry in the existing ride/R2 path. +class FirebaseAccountSyncService { + final AppDatabase _db; + final AuthService _auth; + final FirebaseFirestore? _firestore; + + FirebaseAccountSyncService({ + required AppDatabase db, + required AuthService auth, + FirebaseFirestore? firestore, + }) : _db = db, + _auth = auth, + _firestore = firestore ?? _resolveFirestore(); + + static FirebaseFirestore? _resolveFirestore() { + try { + if (Firebase.apps.isNotEmpty) return FirebaseFirestore.instance; + } catch (_) {} + return null; + } + + bool get isAvailable => _firestore != null && Firebase.apps.isNotEmpty; + + Future syncAccount({DateTime? now}) async { + final user = _auth.currentUser; + if (user == null || user.isAnonymous || !isAvailable) return; + + final timestamp = (now ?? DateTime.now()).toUtc(); + final profile = CloudUserProfile( + id: user.uid, + displayName: user.displayName, + profilePhotoUrl: user.photoUrl, + createdAt: user.createdAt?.toUtc() ?? timestamp, + updatedAt: timestamp, + ); + + final userRef = _firestore!.collection('users').doc(user.uid); + await userRef.set(profile.toJson(), SetOptions(merge: true)); + + final motorcycles = await _db.select(_db.garageMotorcycles).get(); + for (final motorcycle in motorcycles) { + final cloud = CloudMotorcycle( + id: motorcycle.id.toString(), + ownerId: user.uid, + year: motorcycle.year, + makeId: motorcycle.makeId, + makeName: motorcycle.makeName, + modelId: motorcycle.modelId, + modelName: motorcycle.modelName, + variantId: motorcycle.variantId, + variantName: motorcycle.variantName, + nickname: motorcycle.nickname, + isDefault: motorcycle.isDefault, + createdAt: motorcycle.dateAdded.toUtc(), + updatedAt: motorcycle.lastUpdated.toUtc(), + specificationJson: motorcycle.specificationJson, + ); + await userRef.collection('motorcycles').doc(cloud.id).set( + cloud.toJson(), + SetOptions(merge: true), + ); + } + } +}