package bou.amine.apps.readerforselfossv2.android

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.text.TextUtils
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityLoginBinding
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid
import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
import com.mikepenz.aboutlibraries.LibsBuilder
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.acra.ACRA
import org.kodein.di.DIAware
import org.kodein.di.android.closestDI
import org.kodein.di.instance
import java.security.MessageDigest


class LoginActivity : AppCompatActivity(), DIAware {

    private var inValidCount: Int = 0
    private var isWithLogin = false

    private lateinit var binding: ActivityLoginBinding

    override val di by closestDI()
    private val repository: Repository by instance()
    private val appSettingsService: AppSettingsService by instance()


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        handleTheme()

        binding = ActivityLoginBinding.inflate(layoutInflater)
        val view = binding.root

        setContentView(view)

        setSupportActionBar(binding.toolbar)

        handleBaseUrlFail()

        if (appSettingsService.getBaseUrl().isNotEmpty()) {
            showProgress(true)
            // This should be reverted when "old" users connected with a non-selfoss rss
            // are handled. Revert to "simple" way.
            CoroutineScope(Dispatchers.Main).launch {
                try {
                    val (errorFetching, displaySelfossOnly) = repository.shouldBeSelfossInstance()
                    if (!errorFetching && !displaySelfossOnly) {
                        goToMain()
                    } else {
                        showProgress(false)
                        if (displaySelfossOnly) {
                            Toast.makeText(
                                applicationContext,
                                R.string.application_selfoss_only,
                                Toast.LENGTH_LONG
                            ).show()
                        }
                        repository.logout()
                    }
                } catch (e: Throwable) {
                    repository.logout()
                    showProgress(false)
                }
            }
        }

        handleActions()
    }

    @SuppressLint("WrongConstant") // Constant is fetched from the settings
    private fun handleTheme() {
        AppCompatDelegate.setDefaultNightMode(appSettingsService.getCurrentTheme())
    }

    private fun handleActions() {

        binding.passwordView.setOnEditorActionListener(
            TextView.OnEditorActionListener { _, id, _ ->
                if (id == R.id.loginView || id == EditorInfo.IME_NULL) {
                    attemptLogin()
                    return@OnEditorActionListener true
                }
                false
            }
        )

        binding.signInButton.setOnClickListener { attemptLogin() }

        binding.withLogin.setOnCheckedChangeListener { _, b ->
            isWithLogin = !isWithLogin
            val visi: Int = if (b) View.VISIBLE else View.GONE

            binding.loginView.visibility = visi
            binding.passwordView.visibility = visi
        }
    }

    private fun handleBaseUrlFail() {
        if (intent.getBooleanExtra("baseUrlFail", false)) {
            val alertDialog = AlertDialog.Builder(this).create()
            alertDialog.setTitle(getString(R.string.warning_wrong_url))
            alertDialog.setMessage(getString(R.string.base_url_error))
            alertDialog.setButton(
                AlertDialog.BUTTON_NEUTRAL,
                "OK"
            ) { dialog, _ -> dialog.dismiss() }
            alertDialog.show()
        }
    }

    private fun goToMain() {
        CoroutineScope(Dispatchers.Main).launch {
            repository.updateApiVersion()
            ACRA.errorReporter.putCustomData("SELFOSS_API_VERSION", appSettingsService.getApiVersion().toString())
        }
        val intent = Intent(this, HomeActivity::class.java)
        startActivity(intent)
        finish()
    }

    private fun preferenceError() {
        appSettingsService.resetLoginInformation()

        binding.urlView.error = getString(R.string.wrong_infos)
        binding.loginView.error = getString(R.string.wrong_infos)
        binding.passwordView.error = getString(R.string.wrong_infos)
    }

    private fun attemptLogin() {

        // Reset errors.
        binding.urlView.error = null
        binding.loginView.error = null
        binding.passwordView.error = null

        // Store values at the time of the login attempt.
        val url = binding.urlView.text.toString().trim()
        val login = binding.loginView.text.toString().trim()
        val password = binding.passwordView.text.toString().trim()

        var cancel = false
        var focusView: View? = null

        if (url.isBaseUrlInvalid()) {
            binding.urlView.error = getString(R.string.login_url_problem)
            focusView = binding.urlView
            cancel = true
            inValidCount++
            if (inValidCount == 3) {
                val alertDialog = AlertDialog.Builder(this).create()
                alertDialog.setTitle(getString(R.string.warning_wrong_url))
                alertDialog.setMessage(getString(R.string.text_wrong_url))
                alertDialog.setButton(
                    AlertDialog.BUTTON_NEUTRAL,
                    "OK"
                ) { dialog, _ -> dialog.dismiss() }
                alertDialog.show()
                inValidCount = 0
            }
        }

        if (isWithLogin) {
            if (TextUtils.isEmpty(password)) {
                binding.passwordView.error = getString(R.string.error_invalid_password)
                focusView = binding.passwordView
                cancel = true
            }

            if (TextUtils.isEmpty(login)) {
                binding.loginView.error = getString(R.string.error_field_required)
                focusView = binding.loginView
                cancel = true
            }
        }

        if (cancel) {
            focusView?.requestFocus()
        } else {
            showProgress(true)

            repository.refreshLoginInformation(url, login, password)

            CoroutineScope(Dispatchers.Main).launch {
                val result = repository.login()
                if (result) {
                    val (errorFetching, displaySelfossOnly) = repository.shouldBeSelfossInstance()
                    if (!errorFetching && !displaySelfossOnly) {
                        goToMain()
                    } else {
                        if (displaySelfossOnly) {
                            Toast.makeText(
                                applicationContext,
                                R.string.application_selfoss_only,
                                Toast.LENGTH_LONG
                            ).show()
                        }
                        preferenceError()
                    }
                } else {
                    preferenceError()
                }
                showProgress(false)
            }
        }
    }

    private fun showProgress(show: Boolean) {
        val shortAnimTime = resources.getInteger(android.R.integer.config_shortAnimTime)

        binding.loginForm.visibility = if (show) View.GONE else View.VISIBLE
        binding.loginForm
            .animate()
            .setDuration(shortAnimTime.toLong())
            .alpha(
                if (show) 0F else 1F
            ).setListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator) {
                    binding.loginForm.visibility = if (show) View.GONE else View.VISIBLE
                }
            }
            )

        binding.loginProgress.visibility = if (show) View.VISIBLE else View.GONE
        binding.loginProgress
            .animate()
            .setDuration(shortAnimTime.toLong())
            .alpha(
                if (show) 1F else 0F
            ).setListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator) {
                    binding.loginProgress.visibility = if (show) View.VISIBLE else View.GONE
                }
            }
            )
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.login_menu, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            R.id.about -> {
                LibsBuilder()
                    .withAboutIconShown(true)
                    .withAboutVersionShown(true)
                    .start(this)
                true
            }
            else -> super.onOptionsItemSelected(item)
        }
    }
}
