package app.closer.data.repository

import app.closer.data.remote.FirebaseAuthDataSource
import app.closer.domain.model.AuthState
import app.closer.domain.model.GoogleSignInResult
import app.closer.domain.repository.AuthRepository
import app.closer.domain.security.AuthRateLimiter
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class FirebaseAuthRepositoryImpl @Inject constructor(
    private val dataSource: FirebaseAuthDataSource
) : AuthRepository {

    override val authState: Flow<AuthState> = dataSource.authState
    override val currentUserId: String? get() = dataSource.currentUserId
    override val currentUserEmail: String? get() = dataSource.currentUserEmail
    override val currentUserPhotoUrl: String? get() = dataSource.currentUserPhotoUrl
    override val currentUserDisplayName: String? get() = dataSource.currentUserDisplayName
    override val isSignedIn: Boolean get() = dataSource.isSignedIn
    override val isAnonymous: Boolean get() = dataSource.isAnonymous
    override val isGoogleAccount: Boolean get() = dataSource.isGoogleAccount
    override val isEmailVerified: Boolean get() = dataSource.isEmailVerified

    override suspend fun signInWithGoogle(idToken: String): Result<GoogleSignInResult> =
        withRateLimit(AuthRateLimiter.Flow.LOGIN) {
            runCatching { dataSource.signInWithGoogle(idToken) }
        }

    override suspend fun signInWithEmail(email: String, password: String): Result<String> =
        withRateLimit(AuthRateLimiter.Flow.LOGIN) {
            runCatching { dataSource.signInWithEmail(email, password) }
        }

    override suspend fun signUpWithEmail(email: String, password: String): Result<String> =
        withRateLimit(AuthRateLimiter.Flow.SIGN_UP) {
            runCatching { dataSource.signUpWithEmail(email, password) }
        }

    override suspend fun sendEmailVerification(): Result<Unit> =
        runCatching { dataSource.sendEmailVerification() }

    override suspend fun reloadUser(): Result<Unit> =
        runCatching { dataSource.reloadUser() }

    override suspend fun sendPasswordResetEmail(email: String): Result<Unit> =
        withRateLimit(AuthRateLimiter.Flow.PASSWORD_RESET) {
            runCatching { dataSource.sendPasswordResetEmail(email) }
        }

    override suspend fun signOut() = dataSource.signOut()

    override suspend fun reauthenticateWithEmail(email: String, password: String): Result<Unit> =
        runCatching { dataSource.reauthenticateWithEmail(email, password) }

    override suspend fun deleteAccount(): Result<Unit> =
        runCatching { dataSource.deleteAccount() }

    private suspend fun <T> withRateLimit(
        flow: AuthRateLimiter.Flow,
        block: suspend () -> Result<T>
    ): Result<T> {
        val waitMs = AuthRateLimiter.timeUntilNextAttemptMs(flow)
        if (waitMs > 0L) {
            return Result.failure(AuthRateLimiterException(AuthRateLimiter.throttleMessage(flow) ?: "Too many attempts. Please wait."))
        }

        val result = block()
        if (result.isSuccess) {
            AuthRateLimiter.recordSuccess(flow)
        } else {
            AuthRateLimiter.recordFailure(flow)
        }
        return result
    }

    class AuthRateLimiterException(message: String) : Exception(message)
}
