import Foundation

// MARK: - Auth State

enum AuthState: Equatable {
    case loading
    case authenticated(userId: String, isAnonymous: Bool)
    case unauthenticated
}

// MARK: - Auth Rate Limiter

/// Per-session client-side rate limiter for Firebase Auth operations.
/// Mirrors the Android AuthRateLimiter.kt implementation.
final class AuthRateLimiter: @unchecked Sendable {
    static let shared = AuthRateLimiter()
    
    enum Flow: String, CaseIterable {
        case login, signUp, passwordReset, anonymous
    }
    
    private struct AttemptState {
        var failures: Int = 0
        var lockoutEnd: Date?
    }
    
    private let lock = NSLock()
    private var states: [Flow: AttemptState] = [:]
    
    // Constants matching Android
    let softLimitFailures = 3
    let maxFailuresBeforeLockout = 5
    let lockoutDuration: TimeInterval = 30
    let maxBackoff: TimeInterval = 8
    let baseBackoff: TimeInterval = 1
    let backoffExponentBase: Double = 2.0
    
    private init() {}
    
    // How long to wait before next attempt, in seconds
    func timeUntilNextAttempt(_ flow: Flow = .login) -> TimeInterval {
        lock.lock()
        defer { lock.unlock() }
        
        guard let state = states[flow] else { return 0 }
        
        // Check hard lockout
        if let lockoutEnd = state.lockoutEnd, Date() < lockoutEnd {
            return lockoutEnd.timeIntervalSinceNow
        }
        
        return computeBackoffDelay(state.failures)
    }
    
    @discardableResult
    func recordFailure(_ flow: Flow = .login) -> TimeInterval {
        lock.lock()
        defer { lock.unlock() }
        
        var state = states[flow] ?? AttemptState()
        state.failures += 1
        
        if state.failures >= maxFailuresBeforeLockout {
            state.lockoutEnd = Date().addingTimeInterval(lockoutDuration)
        }
        
        states[flow] = state
        
        if let lockoutEnd = state.lockoutEnd, Date() < lockoutEnd {
            return lockoutEnd.timeIntervalSinceNow
        }
        return computeBackoffDelay(state.failures)
    }
    
    func recordSuccess(_ flow: Flow = .login) {
        lock.lock()
        defer { lock.unlock() }
        states.removeValue(forKey: flow)
    }
    
    var isThrottled: Bool {
        timeUntilNextAttempt() > 0
    }
    
    func throttleMessage(_ flow: Flow = .login) -> String? {
        let wait = timeUntilNextAttempt(flow)
        guard wait > 0 else { return nil }
        let seconds = Int(ceil(wait))
        return "Too many attempts. Try again in \(seconds) second\(seconds == 1 ? "" : "s")."
    }
    
    private func computeBackoffDelay(_ failures: Int) -> TimeInterval {
        guard failures >= softLimitFailures else { return 0 }
        let exponent = failures - softLimitFailures
        let raw = baseBackoff * pow(backoffExponentBase, Double(exponent))
        return min(raw, maxBackoff)
    }
}

// MARK: - Google Sign-In Result

struct GoogleSignInResult {
    let uid: String
    let displayName: String
    let photoUrl: String
    let email: String
    let isAnonymous: Bool
}