package pl.firmatpp.kierowca.diagnostics

import com.google.firebase.crashlytics.FirebaseCrashlytics

interface DiagnosticsSink {
    fun log(message: String)
    fun setUserId(userId: String)
    fun setCustomKey(key: String, value: String)
    fun recordException(throwable: Throwable)
}

object NoOpDiagnosticsSink : DiagnosticsSink {
    override fun log(message: String) = Unit
    override fun setUserId(userId: String) = Unit
    override fun setCustomKey(key: String, value: String) = Unit
    override fun recordException(throwable: Throwable) = Unit
}

class FirebaseCrashlyticsDiagnosticsSink(
    private val crashlytics: FirebaseCrashlytics = FirebaseCrashlytics.getInstance(),
) : DiagnosticsSink {
    override fun log(message: String) {
        crashlytics.log(message)
    }

    override fun setUserId(userId: String) {
        crashlytics.setUserId(userId)
    }

    override fun setCustomKey(key: String, value: String) {
        crashlytics.setCustomKey(key, value)
    }

    override fun recordException(throwable: Throwable) {
        crashlytics.recordException(throwable)
    }
}

object AppDiagnostics {
    @Volatile
    private var sink: DiagnosticsSink = NoOpDiagnosticsSink

    fun installFirebaseCrashlytics() {
        installSink(FirebaseCrashlyticsDiagnosticsSink())
    }

    fun installSink(nextSink: DiagnosticsSink) {
        sink = nextSink
    }

    fun setDriverId(driverId: String) {
        sink.setUserId(driverId)
    }

    fun clearDriverId() {
        sink.setUserId("")
    }

    fun log(message: String) {
        sink.log(message)
    }

    fun reportNonFatal(
        throwable: Throwable,
        operation: String,
        keys: Map<String, Any?> = emptyMap(),
    ) {
        sink.setCustomKey("operation", operation)
        keys.forEach { (key, value) ->
            sink.setCustomKey(key, value?.toString().orEmpty())
        }
        sink.log("non_fatal: $operation: ${throwable.message ?: throwable::class.java.simpleName}")
        sink.recordException(throwable)
    }
}
