package com.github.libretube.ui.activities

import android.content.Intent
import android.os.Bundle
import android.text.InputFilter
import android.view.View
import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.lifecycleScope
import com.github.libretube.R
import com.github.libretube.api.PanelAuthHelper
import com.github.libretube.databinding.ActivityAccessCodeBinding
import com.github.libretube.helpers.NetworkHelper
import com.github.libretube.helpers.PreferenceHelper
import com.github.libretube.ui.base.BaseActivity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class AccessCodeActivity : BaseActivity() {
    private var binding: ActivityAccessCodeBinding? = null

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

        binding = ActivityAccessCodeBinding.inflate(layoutInflater)
        setContentView(binding!!.root)

        binding!!.accessCodeInput.filters = arrayOf(InputFilter.LengthFilter(6))
        binding!!.accessCodeInput.doOnTextChanged { text, _, _, _ ->
            binding!!.submitButton.isEnabled = text?.length == 6
            if (text?.length != 6) {
                binding!!.errorText.visibility = View.GONE
            }
        }

        binding!!.accessCodeInput.setOnEditorActionListener { _, actionId, _ ->
            if (actionId == android.view.inputmethod.EditorInfo.IME_ACTION_DONE) {
                submitAccessToken()
                true
            } else {
                false
            }
        }

        binding!!.submitButton.setOnClickListener {
            submitAccessToken()
        }

        val token = PreferenceHelper.getToken().trim()
        if (token.length == 6) {
            binding!!.accessCodeInput.setText(token)
            validateToken(token)
        }

        // If launched due to token expiration, show an error message
        if (intent.getBooleanExtra("expired", false)) {
            showAccessCodeError(R.string.access_code_invalid_or_expired)
        }
    }

    private fun submitAccessToken() {
        val token = binding?.accessCodeInput?.text?.trim()?.toString().orEmpty()
        if (token.length != 6 || token.any { !it.isDigit() }) {
            showAccessCodeError(R.string.access_code_invalid_or_expired)
            return
        }
        validateToken(token)
    }

    private fun validateToken(token: String) {
        if (!NetworkHelper.isNetworkAvailable(this)) {
            val storedToken = PreferenceHelper.getToken().trim()
            if (token == storedToken && token.length == 6) {
                proceedToMainActivity()
            } else {
                showAccessCodeError(R.string.noInternet)
            }
            return
        }

        binding?.progressBar?.visibility = View.VISIBLE
        binding?.submitButton?.isEnabled = false
        binding?.accessCodeInput?.isEnabled = false

        lifecycleScope.launch(Dispatchers.IO) {
            val validationResult = PanelAuthHelper.validarToken(token)
            withContext(Dispatchers.Main) {
                binding?.progressBar?.visibility = View.GONE
                binding?.submitButton?.isEnabled = true
                binding?.accessCodeInput?.isEnabled = true
                if (validationResult.isSuccess &&
                    validationResult.getOrNull()?.status.equals("active", ignoreCase = true)
                ) {
                    PreferenceHelper.setToken(token)
                    proceedToMainActivity()
                } else {
                    PreferenceHelper.clearToken()
                    showAccessCodeError(R.string.access_code_invalid_or_expired)
                }
            }
        }
    }

    private fun proceedToMainActivity() {
        val intent = Intent(this@AccessCodeActivity, MainActivity::class.java)
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
        startActivity(intent)
    }

    private fun showAccessCodeError(messageId: Int) {
        binding?.errorText?.setText(messageId)
        binding?.errorText?.visibility = View.VISIBLE
    }

    override fun onDestroy() {
        binding = null
        super.onDestroy()
    }
}
