package com.tomhempel.rbarometer.ui

import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import android.widget.Spinner
import android.widget.TextView
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import com.tomhempel.rbarometer.LanguageManager
import com.tomhempel.rbarometer.R
import com.tomhempel.rbarometer.network.LoginManager
import com.tomhempel.rbarometer.network.QuestionnaireCache
import com.tomhempel.rbarometer.network.SyncCoordinator
import com.tomhempel.rbarometer.network.TokenStore
import com.tomhempel.rbarometer.questionnaire.AppLanguages
import com.google.android.material.button.MaterialButton
import com.google.android.material.textfield.TextInputEditText
import com.tomhempel.rbarometer.utils.ScreenLoading
import com.tomhempel.rbarometer.utils.ViewUtils
import com.google.android.material.textfield.TextInputLayout
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/**
 * Full-screen login and mandatory password-change flow.
 * Accounts are created on the web by administrators (no self-service signup).
 */
class AuthActivity : AppCompatActivity() {

    private val languageId: String
        get() = AppLanguageStore.get(this)
    private fun t(key: String): String = LanguageManager.getText(languageId, key)

    private lateinit var loginFieldsGroup: View
    private lateinit var changePasswordGroup: View
    private lateinit var tilUsername: TextInputLayout
    private lateinit var tilPassword: TextInputLayout
    private lateinit var tilNewPassword: TextInputLayout
    private lateinit var tilConfirmPassword: TextInputLayout
    private lateinit var etUsername: TextInputEditText
    private lateinit var etPassword: TextInputEditText
    private lateinit var etNewPassword: TextInputEditText
    private lateinit var etConfirmPassword: TextInputEditText
    private lateinit var btnPrimary: MaterialButton
    private lateinit var btnExit: MaterialButton
    private lateinit var authLangSpinner: Spinner
    private lateinit var authLoadingOverlay: View
    private lateinit var authCard: View

    private var uiJob: Job? = null
    private var mode = Mode.LOGIN
    private var suppressLanguageCallback = false

    private var pendingUsername: String = ""
    private var pendingOldPassword: String = ""
    private var pendingTempToken: String = ""

    private enum class Mode { LOGIN, CHANGE_PASSWORD }

    override fun onCreate(savedInstanceState: Bundle?) {
        enableEdgeToEdge()
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_auth)

        SystemBarInsets.applyToContentRoot(this)

        bindViews()
        SyncCoordinator.loadCachedTranslations(this)
        setupLanguageSpinner()
        applyTexts()
        refreshPublicTranslations()

        intent.getStringExtra(EXTRA_PREFILL_USERNAME)?.takeIf { it.isNotBlank() }?.let {
            etUsername.setText(it)
        }

        btnPrimary.setOnClickListener { onPrimaryClick() }
        btnExit.setOnClickListener { finishWithResult(canceled = true) }
    }

    private fun bindViews() {
        loginFieldsGroup = findViewById(R.id.loginFieldsGroup)
        changePasswordGroup = findViewById(R.id.changePasswordGroup)
        tilUsername = findViewById(R.id.tilUsername)
        tilPassword = findViewById(R.id.tilPassword)
        tilNewPassword = findViewById(R.id.tilNewPassword)
        tilConfirmPassword = findViewById(R.id.tilConfirmPassword)
        etUsername = findViewById(R.id.etUsername)
        etPassword = findViewById(R.id.etPassword)
        etNewPassword = findViewById(R.id.etNewPassword)
        etConfirmPassword = findViewById(R.id.etConfirmPassword)
        btnPrimary = findViewById(R.id.btnPrimary)
        btnExit = findViewById(R.id.btnExit)
        authLangSpinner = findViewById(R.id.authLangSpinner)
        authLoadingOverlay = findViewById(R.id.authLoadingOverlay)
        authCard = findViewById(R.id.authCard)
    }

    private fun refreshPublicTranslations() {
        uiJob?.cancel()
        uiJob = CoroutineScope(Dispatchers.Main).launch {
            val updated = withContext(Dispatchers.IO) {
                SyncCoordinator.refreshPublicTranslations(this@AuthActivity)
            }
            if (updated) applyTexts()
        }
    }

    private fun applyTexts() {
        findViewById<TextView>(R.id.authTitle).text = t("auth_title")
        findViewById<TextView>(R.id.authFooter).text = t("auth_footer_accounts")
        btnExit.text = t("exit_btn")
        tilUsername.hint = t("username_hint")
        tilPassword.hint = t("password_hint")
        tilNewPassword.hint = t("new_password_hint")
        tilConfirmPassword.hint = t("confirm_password_hint")
        updateModeUi()
    }

    private fun setupLanguageSpinner() {
        fun bindAdapter() {
            val labels = AppLanguages.spinnerLabels(languageId)
            val selected = labels.getOrNull(AppLanguages.indexOf(languageId))
            ViewUtils.setupLanguagePickerSpinner(this, authLangSpinner, labels, selected)
        }
        bindAdapter()
        authLangSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
                if (suppressLanguageCallback) return
                val newLang = AppLanguages.ids[position]
                if (newLang == languageId) return
                AppLanguageStore.set(this@AuthActivity, newLang)
                suppressLanguageCallback = true
                bindAdapter()
                authLangSpinner.setSelection(AppLanguages.indexOf(newLang), false)
                suppressLanguageCallback = false
                applyTexts()
            }

            override fun onNothingSelected(parent: AdapterView<*>?) = Unit
        }
        suppressLanguageCallback = true
        authLangSpinner.setSelection(AppLanguages.indexOf(languageId), false)
        suppressLanguageCallback = false
    }

    private fun updateModeUi() {
        when (mode) {
            Mode.LOGIN -> {
                loginFieldsGroup.visibility = View.VISIBLE
                changePasswordGroup.visibility = View.GONE
                findViewById<TextView>(R.id.authSubtitle).text = t("auth_subtitle_login")
                btnPrimary.text = t("login_btn")
                btnExit.visibility = View.VISIBLE
            }
            Mode.CHANGE_PASSWORD -> {
                loginFieldsGroup.visibility = View.GONE
                changePasswordGroup.visibility = View.VISIBLE
                findViewById<TextView>(R.id.authSubtitle).text = t("auth_subtitle_change_password")
                btnPrimary.text = t("save_password_btn")
                btnExit.visibility = View.GONE
            }
        }
    }

    private fun onPrimaryClick() {
        when (mode) {
            Mode.LOGIN -> performLogin()
            Mode.CHANGE_PASSWORD -> performChangePassword()
        }
    }

    private fun performLogin() {
        tilUsername.error = null
        tilPassword.error = null

        val user = etUsername.text?.toString()?.trim().orEmpty()
        val pass = etPassword.text?.toString().orEmpty()
        if (user.isEmpty() || pass.isEmpty()) {
            Toast.makeText(this, t("please_username_password"), Toast.LENGTH_SHORT).show()
            return
        }

        setBusy(true)
        uiJob?.cancel()
        uiJob = CoroutineScope(Dispatchers.Main).launch {
            LoginManager.login(
                context = this@AuthActivity,
                username = user,
                password = pass,
                onMustChangePassword = { tempToken, username ->
                    pendingUsername = username
                    pendingOldPassword = pass
                    pendingTempToken = tempToken
                    mode = Mode.CHANGE_PASSWORD
                    updateModeUi()
                    setBusy(false)
                },
                onSuccess = { token, username, assignedClients ->
                    withContext(Dispatchers.IO) {
                        persistSession(token, username, assignedClients)
                    }
                    setBusy(false)
                    finishWithResult(token = token)
                },
                onError = { msg ->
                    setBusy(false)
                    val txt = t("login_failed_with_reason").replace("{reason}", msg)
                    Toast.makeText(this@AuthActivity, txt, Toast.LENGTH_LONG).show()
                }
            )
        }
    }

    private fun performChangePassword() {
        tilNewPassword.error = null
        tilConfirmPassword.error = null

        val newPass = etNewPassword.text?.toString().orEmpty()
        val confirm = etConfirmPassword.text?.toString().orEmpty()

        when {
            newPass.length < 6 -> {
                tilNewPassword.error = t("password_too_short")
                return
            }
            newPass != confirm -> {
                tilConfirmPassword.error = t("passwords_dont_match")
                return
            }
        }

        setBusy(true)
        uiJob?.cancel()
        uiJob = CoroutineScope(Dispatchers.Main).launch {
            LoginManager.changePassword(
                context = this@AuthActivity,
                token = pendingTempToken,
                username = pendingUsername,
                oldPassword = pendingOldPassword,
                newPassword = newPass,
                onSuccess = { token, username, assignedClients ->
                    withContext(Dispatchers.IO) {
                        persistSession(token, username, assignedClients)
                    }
                    setBusy(false)
                    finishWithResult(token = token)
                },
                onError = { msg ->
                    setBusy(false)
                    Toast.makeText(this@AuthActivity, msg, Toast.LENGTH_LONG).show()
                }
            )
        }
    }

    private suspend fun persistSession(token: String, username: String, assignedClients: List<String>) {
        QuestionnaireCache.clearAllClientData(this)
        TokenStore.save(this, token, username)
        QuestionnaireCache.replaceAssignedClients(this, assignedClients)
    }

    private fun setBusy(busy: Boolean) {
        ScreenLoading.setVisible(authLoadingOverlay, busy, authCard)
        btnPrimary.isEnabled = !busy
        btnExit.isEnabled = !busy
        authLangSpinner.isEnabled = !busy
        etUsername.isEnabled = !busy
        etPassword.isEnabled = !busy
        etNewPassword.isEnabled = !busy
        etConfirmPassword.isEnabled = !busy
    }

    private fun finishWithResult(token: String? = null, canceled: Boolean = false) {
        if (canceled) {
            setResult(RESULT_CANCELED)
        } else {
            setResult(RESULT_OK, Intent().putExtra(EXTRA_TOKEN, token))
        }
        finish()
    }

    override fun onDestroy() {
        uiJob?.cancel()
        super.onDestroy()
    }

    companion object {
        const val EXTRA_PREFILL_USERNAME = "prefill_username"
        const val EXTRA_TOKEN = "token"
    }
}
