package app.closer.data.remote

import app.closer.BuildConfig
import app.closer.domain.model.AuthState
import app.closer.domain.model.GoogleSignInResult
import com.google.firebase.auth.EmailAuthProvider
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.GoogleAuthProvider
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.suspendCancellableCoroutine
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException

@Singleton
class FirebaseAuthDataSource @Inject constructor() {

    private val auth = FirebaseAuth.getInstance().also {
        if (BuildConfig.DEBUG) it.firebaseAuthSettings.setAppVerificationDisabledForTesting(true)
    }

    val currentUserId: String? get() = auth.currentUser?.uid
    val currentUserEmail: String? get() = auth.currentUser?.email
    /** Provider profile photo (e.g. the Google avatar) — fallback when the user doc has none yet. */
    val currentUserPhotoUrl: String? get() = auth.currentUser?.photoUrl?.toString()
    val currentUserDisplayName: String? get() = auth.currentUser?.displayName
    val isSignedIn: Boolean get() = auth.currentUser != null
    val isAnonymous: Boolean get() = auth.currentUser?.isAnonymous ?: false
    val isEmailVerified: Boolean get() = auth.currentUser?.isEmailVerified ?: false
    val isGoogleAccount: Boolean
        get() = auth.currentUser?.providerData?.any { it.providerId == GoogleAuthProvider.PROVIDER_ID } == true

    val authState: Flow<AuthState> = callbackFlow {
        trySend(snapshot())
        val listener = FirebaseAuth.AuthStateListener { fa ->
            trySend(
                fa.currentUser?.let { AuthState.Authenticated(it.uid, it.isAnonymous) }
                    ?: AuthState.Unauthenticated
            )
        }
        auth.addAuthStateListener(listener)
        awaitClose { auth.removeAuthStateListener(listener) }
    }

    private fun snapshot(): AuthState =
        auth.currentUser?.let { AuthState.Authenticated(it.uid, it.isAnonymous) }
            ?: AuthState.Unauthenticated

    suspend fun signInWithEmail(email: String, password: String): String =
        suspendCancellableCoroutine { cont ->
            auth.signInWithEmailAndPassword(email, password)
                .addOnSuccessListener { cont.resume(it.user?.uid ?: "") }
                .addOnFailureListener { cont.resumeWithException(it) }
        }

    suspend fun signUpWithEmail(email: String, password: String): String =
        suspendCancellableCoroutine { cont ->
            auth.createUserWithEmailAndPassword(email, password)
                .addOnSuccessListener { cont.resume(it.user?.uid ?: "") }
                .addOnFailureListener { cont.resumeWithException(it) }
        }

    suspend fun sendEmailVerification(): Unit =
        suspendCancellableCoroutine { cont ->
            val user = auth.currentUser
            if (user == null) {
                cont.resumeWithException(IllegalStateException("No signed-in user"))
                return@suspendCancellableCoroutine
            }
            user.sendEmailVerification()
                .addOnSuccessListener { cont.resume(Unit) }
                .addOnFailureListener { cont.resumeWithException(it) }
        }

    /** Refreshes the cached FirebaseUser so [isEmailVerified] reflects server state. */
    suspend fun reloadUser(): Unit =
        suspendCancellableCoroutine { cont ->
            val user = auth.currentUser
            if (user == null) {
                cont.resumeWithException(IllegalStateException("No signed-in user"))
                return@suspendCancellableCoroutine
            }
            user.reload()
                .addOnSuccessListener { cont.resume(Unit) }
                .addOnFailureListener { cont.resumeWithException(it) }
        }

    suspend fun sendPasswordResetEmail(email: String): Unit =
        suspendCancellableCoroutine { cont ->
            auth.sendPasswordResetEmail(email)
                .addOnSuccessListener { cont.resume(Unit) }
                .addOnFailureListener { cont.resumeWithException(it) }
        }

    suspend fun signInWithGoogle(idToken: String): GoogleSignInResult =
        suspendCancellableCoroutine { cont ->
            val credential = GoogleAuthProvider.getCredential(idToken, null)
            auth.signInWithCredential(credential)
                .addOnSuccessListener { result ->
                    val user = auth.currentUser ?: result.user
                    cont.resume(
                        GoogleSignInResult(
                            uid = user?.uid ?: "",
                            displayName = user?.displayName ?: "",
                            photoUrl = user?.photoUrl?.toString() ?: "",
                            email = user?.email ?: "",
                            isAnonymous = user?.isAnonymous ?: false
                        )
                    )
                }
                .addOnFailureListener { cont.resumeWithException(it) }
        }

    fun signOut() = auth.signOut()

    suspend fun reauthenticateWithEmail(email: String, password: String): Unit =
        suspendCancellableCoroutine { cont ->
            val credential = EmailAuthProvider.getCredential(email, password)
            auth.currentUser
                ?.reauthenticate(credential)
                ?.addOnSuccessListener { cont.resume(Unit) }
                ?.addOnFailureListener { cont.resumeWithException(it) }
                ?: cont.resumeWithException(IllegalStateException("No signed-in user"))
        }

    suspend fun deleteAccount(): Unit =
        suspendCancellableCoroutine { cont ->
            auth.currentUser
                ?.delete()
                ?.addOnSuccessListener { cont.resume(Unit) }
                ?.addOnFailureListener { cont.resumeWithException(it) }
                ?: cont.resumeWithException(IllegalStateException("No signed-in user"))
        }
}
