package com.sinch.android.rtc.sample.hmspush

import android.app.ProgressDialog
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.KeyEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import com.sinch.android.rtc.*
import com.sinch.android.rtc.sample.hmspush.JWT.create
import com.sinch.android.rtc.sample.hmspush.PersistedHmsRegistration.setHmsApplicationId
import com.sinch.android.rtc.sample.hmspush.PersistedHmsRegistration.setHmsToken
import com.sinch.android.rtc.sample.hmspush.hms.RegisterToHmsTask
import java.io.IOException

class LoginActivity : BaseActivity(), SinchService.StartFailedListener,
    PushTokenRegistrationCallback, UserRegistrationCallback,
    RegisterToHmsTask.RegistrationCallback {

    private lateinit var loginButton: Button
    private lateinit var loginNameEditText: EditText

    private var progressSpinner: ProgressDialog? = null
    private var userId: String? = null
    private var hmsDeviceToken: String? = null
    private var hmsApplicationId: String? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.login)
        loginNameEditText = findViewById(R.id.loginName)
        loginButton = findViewById(R.id.loginButton)

        loginNameEditText.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
            if (actionId == EditorInfo.IME_ACTION_DONE) {
                loginClicked()
                return@setOnEditorActionListener true
            }
            false
        }
        loginButton.apply {
            isEnabled = false
            setOnClickListener { loginClicked() }
        }
    }

    override fun onResume() {
        super.onResume()
        if (hmsDeviceToken?.isNotEmpty() == true) {
            loginButton.isEnabled = true
            loginButton.visibility = View.VISIBLE
        } else {
            // Huawei recommends reacquiring the Device Token each app start.
            // For simplicity of UI handling we demonstrate it here.
            loginButton.visibility = View.INVISIBLE
            RegisterToHmsTask(applicationContext, this).execute()
        }
    }

    override fun onServiceConnected() {
        if (sinchServiceInterface?.isStarted == true) {
            openPlaceCallActivity()
        } else {
            sinchServiceInterface?.setStartListener(this)
        }
    }

    override fun onPause() {
        dismissSpinner()
        super.onPause()
    }

    override fun onFailed(error: SinchError) {
        Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show()
        dismissSpinner()
    }

    override fun onStarted() {
        openPlaceCallActivity()
    }

    private fun startClientAndOpenPlaceCallActivity() {
        // Start Sinch Client, it'll result onStarted() callback from where the place call
        // activity will be started
        if (sinchServiceInterface?.isStarted == false) {
            sinchServiceInterface?.startClient()
            showSpinner()
        }
    }

    private fun loginClicked() {
        val username = loginNameEditText.text.toString()
        sinchServiceInterface?.username = username
        if (username.isEmpty()) {
            Toast.makeText(this, "Please enter a name", Toast.LENGTH_LONG).show()
            return
        }

        /**
         * For the login flow we showcase UserController usage here. It's a lightweight component
         * that can be use to register the user for receiving push notifications without the need
         * to initialize the entire SinchClient.
         *
         * SinchClient provides exactly same functionality when started.
         *
         */
        userId = username
        val userController = try {
            UserController.builder()
                .context(applicationContext)
                .applicationKey(SinchService.APP_KEY)
                .userId(userId.orEmpty())
                .environmentHost(SinchService.ENVIRONMENT)
                .pushConfiguration(
                    PushConfiguration.hmsPushConfigurationBuilder()
                        .applicationId(hmsApplicationId.orEmpty())
                        .deviceToken(hmsDeviceToken.orEmpty())
                        .build()
                )
                .build()
        } catch (e: IOException) {
            Log.e(TAG, "Error while building user controller", e)
            return
        }
        userController.registerUser(this, this)
    }

    private fun openPlaceCallActivity() {
        startActivity(Intent(this, PlaceCallActivity::class.java))
    }

    private fun showSpinner() {
        progressSpinner = ProgressDialog(this).apply {
            setTitle("Logging in")
            setMessage("Please wait...")
            show()
        }
    }

    private fun dismissSpinner() {
        progressSpinner?.dismiss()
    }

    override fun onUserRegistrationFailed(error: SinchError) {
        dismissSpinner()
        Toast.makeText(this, "Registration failed!", Toast.LENGTH_LONG).show()
    }

    override fun onUserRegistered() {
        // Instance is registered, but we'll wait for another callback, assuring that the push
        // token is registered as well, meaning we can receive incoming calls.
    }

    override fun onPushTokenRegistered() {
        dismissSpinner()
        startClientAndOpenPlaceCallActivity()
    }

    override fun onPushTokenRegistrationFailed(error: SinchError) {
        dismissSpinner()
        Toast.makeText(
            this, "Push token registration failed - incoming calls can't be received!",
            Toast.LENGTH_LONG
        ).show()
    }

    // The most secure way is to obtain the credentials from the backend,
    // since storing the Application Secret in the app is not safe.
    // Following code demonstrates how the JWT that serves as credential should be created,
    // provided the Application Key (APP_KEY), Application Secret (APP_SECRET) and User ID.
    override fun onCredentialsRequired(clientRegistration: ClientRegistration) {
        // NB: This implementation just emulates what should be an async procedure, with JWT
        // .create() being  run on your backend.
        clientRegistration.register(
            create(
                SinchService.APP_KEY,
                SinchService.APP_SECRET,
                userId.orEmpty()
            )
        )
    }

    override fun onRegisterComplete(deviceToken: String?, applicationId: String?) {
        hmsDeviceToken = deviceToken
        hmsApplicationId = applicationId
        if (hmsDeviceToken == null || hmsApplicationId?.isEmpty() == true) {
            Toast.makeText(
                this, "Failed to get HMS Device Token. Make sure that the app is signed and the "
                        + "signature's fingerprint is uploaded to the Huawei AppGallery console.",
                Toast.LENGTH_LONG
            ).show()
            loginButton.isEnabled = false
            return
        } else {
            // Store HMS registration data to use it when creating SinchClient.
            setHmsToken(applicationContext, hmsDeviceToken)
            setHmsApplicationId(
                applicationContext,
                hmsApplicationId
            )
            loginButton.visibility = View.VISIBLE
            loginButton.isEnabled = true
        }
    }

    companion object {
        private val TAG = LoginActivity::class.java.simpleName
    }
}