package com.aistudio.bonjuteri.jwlry.data import android.content.Context import android.util.Log import com.aistudio.bonjuteri.jwlry.model.UserProfile import com.aistudio.bonjuteri.jwlry.model.UserRole import com.google.firebase.Timestamp import com.google.firebase.auth.AuthCredential import com.google.firebase.auth.FirebaseAuth import com.google.firebase.auth.FirebaseAuthException import com.google.firebase.auth.FirebaseUser import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.SetOptions import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import kotlinx.coroutines.tasks.await class AuthRepository( private val auth: FirebaseAuth, private val firestore: FirebaseFirestore ) { companion object { private const val TAG = "AuthRepository" const val SUPER_ADMIN_EMAIL = "info@raappstudio.online" private const val USERS_COLLECTION = "users" @Volatile private var INSTANCE: AuthRepository? = null fun getInstance(context: Context): AuthRepository { return INSTANCE ?: synchronized(this) { INSTANCE ?: AuthRepository( FirebaseAuth.getInstance(), FirestoreHelper.getFirestore(context) ).also { INSTANCE = it } } } } private val repositoryScope = CoroutineScope(Dispatchers.IO) private val _userProfileState = MutableStateFlow(null) val userProfileState: StateFlow = _userProfileState.asStateFlow() private val _isAuthReady = MutableStateFlow(false) val isAuthReady: StateFlow = _isAuthReady.asStateFlow() init { auth.addAuthStateListener { firebaseAuth -> val firebaseUser = firebaseAuth.currentUser if (firebaseUser != null) { repositoryScope.launch { try { val profile = loadOrCreateProfile(firebaseUser) _userProfileState.value = profile } catch (e: Throwable) { Log.e(TAG, "Auth state profil yükleme hatası (offline): ${e.message}", e) val nameParts = (firebaseUser.displayName ?: "").split(" ") val firstName = nameParts.firstOrNull() ?: "" val lastName = if (nameParts.size > 1) nameParts.drop(1).joinToString(" ") else "" val isSuperAdmin = firebaseUser.email?.equals(SUPER_ADMIN_EMAIL, ignoreCase = true) == true _userProfileState.value = UserProfile( id = firebaseUser.uid, email = firebaseUser.email ?: "", firstName = firstName, lastName = lastName, role = if (isSuperAdmin) UserRole.SUPER_ADMIN.name else UserRole.USER.name ) } finally { _isAuthReady.value = true } } } else { _userProfileState.value = null _isAuthReady.value = true } } } val currentFirebaseUser: FirebaseUser? get() = auth.currentUser val isUserLoggedIn: Boolean get() = auth.currentUser != null suspend fun signUpWithEmail( firstName: String, lastName: String, email: String, password: String, phone: String = "" ): Result { return try { val trimmedEmail = email.trim() val trimmedPassword = password.trim() val trimmedFirst = firstName.trim() val trimmedLast = lastName.trim() if (trimmedFirst.isBlank() || trimmedLast.isBlank()) { return Result.failure(IllegalArgumentException("Lütfen adınızı ve soyadınızı eksiksiz giriniz.")) } if (!android.util.Patterns.EMAIL_ADDRESS.matcher(trimmedEmail).matches()) { return Result.failure(IllegalArgumentException("Lütfen geçerli bir e-posta adresi giriniz.")) } if (trimmedPassword.length < 6) { return Result.failure(IllegalArgumentException("Şifreniz en az 6 karakter olmalıdır.")) } val authResult = auth.createUserWithEmailAndPassword(trimmedEmail, trimmedPassword).await() val user = authResult.user ?: throw IllegalStateException("Kayıt işlemi sonrasında kullanıcı oluşturulamadı.") val assignedRole = if (trimmedEmail.equals(SUPER_ADMIN_EMAIL, ignoreCase = true)) { UserRole.SUPER_ADMIN.name } else { UserRole.USER.name } val newProfile = UserProfile( id = user.uid, email = trimmedEmail, firstName = trimmedFirst, lastName = trimmedLast, phone = phone.trim(), role = assignedRole, createdAt = Timestamp.now(), updatedAt = Timestamp.now() ) try { firestore.collection(USERS_COLLECTION) .document(user.uid) .set(newProfile) .await() } catch (e: Exception) { Log.w(TAG, "Profil Firestore'a yazılırken ağ uyarısı (offline olabilir): ${e.message}") } _userProfileState.value = newProfile Result.success(newProfile) } catch (e: Throwable) { Log.e(TAG, "Kayıt hatası: ${e.message}", e) Result.failure(mapAuthException(e)) } } suspend fun signInWithEmail(email: String, password: String): Result { return try { val trimmedEmail = email.trim() val trimmedPassword = password.trim() if (trimmedEmail.isBlank() || trimmedPassword.isBlank()) { return Result.failure(IllegalArgumentException("Lütfen e-posta ve şifrenizi giriniz.")) } val authResult = auth.signInWithEmailAndPassword(trimmedEmail, trimmedPassword).await() val user = authResult.user ?: throw IllegalStateException("Kullanıcı bilgisi alınamadı.") val profile = loadOrCreateProfile(user) _userProfileState.value = profile Result.success(profile) } catch (e: Throwable) { Log.e(TAG, "Giriş hatası: ${e.message}", e) Result.failure(mapAuthException(e)) } } suspend fun sendPasswordReset(email: String): Result { return try { val trimmedEmail = email.trim() if (trimmedEmail.isBlank()) { return Result.failure(IllegalArgumentException("Lütfen e-posta adresinizi giriniz.")) } auth.sendPasswordResetEmail(trimmedEmail).await() Result.success(Unit) } catch (e: Throwable) { Log.e(TAG, "Şifre sıfırlama hatası: ${e.message}", e) Result.failure(mapAuthException(e)) } } suspend fun signInWithCredential(credential: AuthCredential): Result { return try { val authResult = auth.signInWithCredential(credential).await() val user = authResult.user ?: throw IllegalStateException("Kimlik doğrulanamadı.") val profile = loadOrCreateProfile(user) _userProfileState.value = profile Result.success(profile) } catch (e: Throwable) { Log.e(TAG, "Credential giriş hatası: ${e.message}", e) Result.failure(mapAuthException(e)) } } suspend fun refreshUserProfile(): UserProfile? { val user = auth.currentUser ?: return null return try { val profile = loadOrCreateProfile(user) _userProfileState.value = profile profile } catch (e: Exception) { Log.e(TAG, "Profil yenileme hatası: ${e.message}", e) _userProfileState.value } } fun signOut() { auth.signOut() _userProfileState.value = null } private suspend fun loadOrCreateProfile(user: FirebaseUser): UserProfile { val isSuperAdminEmail = user.email?.equals(SUPER_ADMIN_EMAIL, ignoreCase = true) == true val nameParts = (user.displayName ?: "").split(" ") val firstName = nameParts.firstOrNull() ?: "" val lastName = if (nameParts.size > 1) nameParts.drop(1).joinToString(" ") else "" // 1. Verify token custom claims for role if assigned by backend Admin SDK val tokenResult = try { user.getIdToken(false).await() } catch (_: Exception) { null } val customClaimRole = tokenResult?.claims?.get("role") as? String val fallbackRole = when { !customClaimRole.isNullOrBlank() -> customClaimRole isSuperAdminEmail -> UserRole.SUPER_ADMIN.name else -> UserRole.USER.name } val fallbackProfile = UserProfile( id = user.uid, email = user.email ?: "", firstName = firstName, lastName = lastName, phone = user.phoneNumber ?: "", role = fallbackRole, createdAt = Timestamp.now(), updatedAt = Timestamp.now() ) val userDoc = try { firestore.collection(USERS_COLLECTION).document(user.uid).get().await() } catch (e: Exception) { Log.w(TAG, "Kullanıcı dokümanı alınamadı (offline veya bağlantı hatası): ${e.message}") null } if (userDoc != null && userDoc.exists()) { val existing = userDoc.toObject(UserProfile::class.java) ?: fallbackProfile val finalRole = when { !customClaimRole.isNullOrBlank() -> customClaimRole isSuperAdminEmail -> UserRole.SUPER_ADMIN.name else -> existing.role.ifBlank { UserRole.USER.name } } if (finalRole != existing.role) { val updated = existing.copy(role = finalRole, updatedAt = Timestamp.now()) try { firestore.collection(USERS_COLLECTION).document(user.uid) .set(mapOf("role" to finalRole, "updatedAt" to Timestamp.now()), SetOptions.merge()) .await() } catch (e: Exception) { Log.w(TAG, "Rol güncelleme uyarısı: ${e.message}") } return updated } return existing } else if (userDoc != null && !userDoc.exists()) { // New user registration / initial Google sign in try { firestore.collection(USERS_COLLECTION).document(user.uid).set(fallbackProfile).await() } catch (e: Exception) { Log.w(TAG, "Yeni profil kaydı oluşturulurken uyarı (offline): ${e.message}") } return fallbackProfile } else { // Document could not be fetched due to client offline return fallbackProfile } } private fun mapAuthException(e: Throwable): Exception { if (e !is FirebaseAuthException) return Exception(e.localizedMessage ?: "İşlem gerçekleştirilemedi.") val trMessage = when (e.errorCode) { "ERROR_INVALID_EMAIL" -> "Geçersiz e-posta formatı." "ERROR_WRONG_PASSWORD" -> "Girdiğiniz şifre hatalı." "ERROR_USER_NOT_FOUND" -> "Bu e-posta adresine kayıtlı bir kullanıcı bulunamadı." "ERROR_USER_DISABLED" -> "Bu hesap devre dışı bırakılmıştır." "ERROR_TOO_MANY_REQUESTS" -> "Çok fazla başarısız deneme yapıldı. Lütfen biraz sonra tekrar deneyiniz." "ERROR_EMAIL_ALREADY_IN_USE" -> "Bu e-posta adresi zaten kullanımda." "ERROR_WEAK_PASSWORD" -> "Belirlenen şifre çok zayıf. Lütfen en az 6 karakterli güçlü bir şifre seçiniz." "ERROR_NETWORK_REQUEST_FAILED" -> "İnternet bağlantınızı kontrol ediniz." else -> e.localizedMessage ?: "Kimlik doğrulama hatası." } return Exception(trMessage) } }