/*
 * Copyright © All Contributors. See LICENSE and AUTHORS in the root directory for details.
 */
package at.bitfire.davdroid.sync.account

import android.accounts.Account
import android.accounts.AccountManager
import androidx.test.platform.app.InstrumentationRegistry
import at.bitfire.davdroid.R
import at.bitfire.davdroid.settings.AccountSettings
import at.bitfire.davdroid.sync.account.TestAccount.remove
import at.bitfire.synctools.util.AndroidAccountUtils
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue

object TestAccount {

    private val targetContext by lazy { InstrumentationRegistry.getInstrumentation().targetContext }

    /**
     * Creates a test account, usually in the `Before` setUp of a test.
     *
     * Remove it with [remove].
     */
    fun create(version: Int = AccountSettings.CURRENT_VERSION, accountName: String = "Test Account"): Account {
        val accountType = targetContext.getString(R.string.account_type)
        val account = Account(accountName, accountType)

        val initialData = AccountSettings.initialUserData(null, null).toMutableMap()
        // overwrite settings version
        initialData[AccountSettings.KEY_SETTINGS_VERSION] = version.toString()

        assertTrue(AndroidAccountUtils.createAccount(targetContext, account, initialData))
        return account
    }

    /**
     * Renames a test account in a blocking way (usually what you want in tests)
     */
    fun rename(account: Account, newName: String): Account {
        val am = AccountManager.get(targetContext)
        val newAccount = am.renameAccount(account, newName, null, null).result
        assertEquals(newName, newAccount.name)
        return newAccount
    }

    /**
     * Removes a test account, usually in the `@After` tearDown of a test.
     */
    fun remove(account: Account) {
        val am = AccountManager.get(targetContext)
        assertTrue(am.removeAccountExplicitly(account))
    }

    /**
     * Convenience method to create a test account and remove it after executing the block.
     */
    fun provide(version: Int = AccountSettings.CURRENT_VERSION, block: (Account) -> Unit) {
        val account = create(version)
        try {
            block(account)
        } finally {
            remove(account)
        }
    }

}
