package de.sebse.fuplanner2.auth

import android.accounts.*
import android.accounts.AccountManager.KEY_BOOLEAN_RESULT
import android.content.Context
import android.os.Build
import android.os.Bundle
import android.text.TextUtils
import com.android.volley.VolleyError
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async


class FuplannerAccountAuthenticator(ctx: Context) : AbstractAccountAuthenticator(ctx) {
    private val context: Context = ctx.applicationContext
    override fun editProperties(
        accountAuthenticatorResponse: AccountAuthenticatorResponse,
        s: String
    ): Bundle? {
        return null
    }

    @Throws(NetworkErrorException::class)
    override fun addAccount(
        response: AccountAuthenticatorResponse?,
        accountType: String?,
        authTokenType: String?,
        requiredFeatures: Array<String>?,
        options: Bundle?
    ): Bundle {
        return Bundle().apply {
            val intent = FuplannerAccountActivity.createIntent(
                context,
                true,
                accountType,
                response = response,
                authTokenType = authTokenType
            )
            putParcelable(AccountManager.KEY_INTENT, intent)
        }
    }

    @Throws(NetworkErrorException::class)
    override fun confirmCredentials(
        accountAuthenticatorResponse: AccountAuthenticatorResponse,
        account: Account,
        bundle: Bundle
    ): Bundle? {
        return null
    }

    @Throws(NetworkErrorException::class)
    override fun getAuthToken(
        response: AccountAuthenticatorResponse,
        account: Account,
        authTokenType: String,
        options: Bundle
    ): Bundle? {
        val accountManager = AccountManager.get(context)
        var authToken = accountManager.peekAuthToken(account, authTokenType)
        if (TextUtils.isEmpty(authToken)) {
            val password = accountManager.getPassword(account)
            if (password != null) {
                val result = Bundle()
                GlobalScope.async {
                    authToken = FuplannerAccountHelper.authenticate(
                        context,
                        account.name,
                        password,
                        false
                    )
                    result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name)
                    result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type)
                    result.putString(AccountManager.KEY_AUTHTOKEN, authToken)
                }.invokeOnCompletion {
                    if (it == null) {
                        response.onResult(result)
                        return@invokeOnCompletion
                    }
                    var message = it.message
                    val code = if (it is VolleyError) {
                        when (it.networkResponse.statusCode) {
                            403 -> { // Auth failed / wrong credentials
                                message = FuplannerAccountConstants.MSG_INVALID_CREDENTIALS
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2)
                                    AccountManager.ERROR_CODE_BAD_AUTHENTICATION
                                else
                                    AccountManager.ERROR_CODE_BAD_ARGUMENTS
                            }
                            422 // Processing failed; MAYBE auth failed / wrong credentials
                            -> AccountManager.ERROR_CODE_CANCELED
                            418 // Timeout
                            -> AccountManager.ERROR_CODE_NETWORK_ERROR
                            else // Other network error
                            -> AccountManager.ERROR_CODE_NETWORK_ERROR
                        }
                    } else { // Other undefined error
                        AccountManager.ERROR_CODE_CANCELED
                    }
                    response.onError(code, message)
                }
                return null
            } else {
                return Bundle().apply {
                    val intent = FuplannerAccountActivity.createIntent(
                        context,
                        true,
                        account.type,
                        accountName = account.name,
                        response = response,
                        authTokenType = authTokenType
                    )
                    putParcelable(AccountManager.KEY_INTENT, intent)
                }
            }
        } else {
            // Token found and returned
            val result = Bundle()
            result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name)
            result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type)
            result.putString(AccountManager.KEY_AUTHTOKEN, authToken)
            return result
        }
    }

    override fun getAuthTokenLabel(s: String): String {
        return "full"
    }

    @Throws(NetworkErrorException::class)
    override fun updateCredentials(
        accountAuthenticatorResponse: AccountAuthenticatorResponse,
        account: Account,
        s: String,
        bundle: Bundle
    ): Bundle? {
        return null
    }

    @Throws(NetworkErrorException::class)
    override fun hasFeatures(
        accountAuthenticatorResponse: AccountAuthenticatorResponse,
        account: Account,
        strings: Array<String>
    ): Bundle {
        val result = Bundle()
        result.putBoolean(KEY_BOOLEAN_RESULT, false)
        return result
    }
}