package chat.rocket.android.infrastructure

import android.app.Application
import chat.rocket.android.BuildConfig
import chat.rocket.android.server.domain.AccountsRepository
import chat.rocket.android.server.domain.GetCurrentServerInteractor
import chat.rocket.android.server.domain.GetSettingsInteractor
import chat.rocket.android.server.domain.SITE_URL
import com.crashlytics.android.Crashlytics
import kotlinx.coroutines.experimental.runBlocking

object CrashlyticsWrapper {

    private const val KEY_CURRENT_SERVER = "CURRENT_SERVER"
    private const val KEY_CURRENT_USER = "CURRENT_USER"
    private const val KEY_CURRENT_USERNAME = "CURRENT_USERNAME"
    private const val KEY_ACCOUNTS = "ACCOUNTS"
    private const val KEY_SETTINGS_SIZE = "SETTINGS_SIZE"
    private const val KEY_SETTINGS_BASE_URL = "SETTINGS_BASE_URL"

    fun install(context: Application,
                currentServerInteractor: GetCurrentServerInteractor,
                settingsInteractor: GetSettingsInteractor,
                accountRepository: AccountsRepository,
                localRepository: LocalRepository) {
        if (isEnabled()) {
            Thread.setDefaultUncaughtExceptionHandler(RocketChatUncaughtExceptionHandler(currentServerInteractor,
                    settingsInteractor, accountRepository, localRepository))
        }
    }

    private fun isEnabled(): Boolean {
        return !BuildConfig.DEBUG
    }

    private class RocketChatUncaughtExceptionHandler(
            val currentServerInteractor: GetCurrentServerInteractor,
            val settingsInteractor: GetSettingsInteractor,
            val accountRepository: AccountsRepository,
            val localRepository: LocalRepository)
        : Thread.UncaughtExceptionHandler {

        val crashlyticsHandler: Thread.UncaughtExceptionHandler? = Thread.getDefaultUncaughtExceptionHandler()

        override fun uncaughtException(t: Thread, e: Throwable) {
            val currentServer = currentServerInteractor.get() ?: "<unknown>"
            Crashlytics.setString(KEY_CURRENT_SERVER, currentServer)
            runBlocking {
                val accounts = accountRepository.load()
                Crashlytics.setString(KEY_ACCOUNTS, accounts.toString())
            }

            val settings = settingsInteractor.get(currentServer)
            Crashlytics.setInt(KEY_SETTINGS_SIZE, settings.size)
            val baseUrl = settings[SITE_URL]?.toString()
            Crashlytics.setString(KEY_SETTINGS_BASE_URL, baseUrl)

            val user = localRepository.getCurrentUser(currentServer)
            Crashlytics.setString(KEY_CURRENT_USER, user?.toString())
            Crashlytics.setString(KEY_CURRENT_USERNAME, localRepository.username())

            if (crashlyticsHandler != null) {
                crashlyticsHandler.uncaughtException(t, e)
            } else {
                throw RuntimeException("Missing default exception handler")
            }
        }
    }
}