package bou.amine.apps.readerforselfossv2.android

import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityUpsertSourceBinding
import bou.amine.apps.readerforselfossv2.android.utils.isBaseUrlInvalid
import bou.amine.apps.readerforselfossv2.model.NetworkUnavailableException
import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.kodein.di.DIAware
import org.kodein.di.android.closestDI
import org.kodein.di.instance

class UpsertSourceActivity : AppCompatActivity(), DIAware {
    private var existingSource: SelfossModel.SourceDetail? = null
    private var mSpoutsValue: String? = null

    private lateinit var binding: ActivityUpsertSourceBinding

    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)
        binding = ActivityUpsertSourceBinding.inflate(layoutInflater)
        val view = binding.root

        existingSource = repository.getSelectedSource()
        if (existingSource != null) {
            binding.formContainer.visibility = View.GONE
            binding.progress.visibility = View.VISIBLE
        }
        val title = if (existingSource == null) R.string.add_source else R.string.update_source

        supportFragmentManager.addOnBackStackChangedListener {
            if (supportFragmentManager.backStackEntryCount == 0) {
                setTitle(title)
            }
        }

        setContentView(view)

        setSupportActionBar(binding.toolbar)
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
        supportActionBar?.setDisplayShowHomeEnabled(true)
        supportActionBar?.title = resources.getString(title)

        maybeGetDetailsFromIntentSharing(intent)

        binding.saveBtn.setOnClickListener {
            handleSaveSource()
        }
    }

    private fun initFields(items: Map<String, SelfossModel.Spout>) {
        binding.nameInput.setText(existingSource!!.title)
        binding.tags.setText(existingSource!!.tags?.joinToString(", "))
        binding.sourceUri.setText(existingSource!!.params?.url)
        binding.spoutsSpinner.setSelection(items.keys.indexOf(existingSource!!.spout))
        binding.progress.visibility = View.GONE
        binding.formContainer.visibility = View.VISIBLE
    }

    override fun onResume() {
        super.onResume()

        val baseUrl = appSettingsService.getBaseUrl()
        if (baseUrl.isEmpty() || baseUrl.isBaseUrlInvalid()) {
            mustLoginToAddSource()
        } else {
            handleSpoutsSpinner()
        }
    }

    private fun handleSpoutsSpinner() {
        val spoutsKV = HashMap<String, String>()
        binding.spoutsSpinner.onItemSelectedListener =
            object : AdapterView.OnItemSelectedListener {
                override fun onItemSelected(
                    adapterView: AdapterView<*>,
                    view: View?,
                    i: Int,
                    l: Long,
                ) {
                    if (view != null) {
                        val spoutName = (view as TextView).text.toString()
                        mSpoutsValue = spoutsKV[spoutName]
                    }
                }

                override fun onNothingSelected(adapterView: AdapterView<*>) {
                    mSpoutsValue = null
                }
            }

        fun handleSpoutFailure(networkIssue: Boolean = false) {
            Toast.makeText(
                this@UpsertSourceActivity,
                if (networkIssue) R.string.cant_get_spouts_no_network else R.string.cant_get_spouts,
                Toast.LENGTH_SHORT,
            ).show()
            binding.progress.visibility = View.GONE
        }

        CoroutineScope(Dispatchers.Main).launch {
            try {
                val items = repository.getSpouts()
                if (items.isNotEmpty()) {
                    val itemsStrings = items.map { it.value.name }
                    for ((key, value) in items) {
                        spoutsKV[value.name] = key
                    }

                    binding.progress.visibility = View.GONE
                    binding.formContainer.visibility = View.VISIBLE

                    val spinnerArrayAdapter =
                        ArrayAdapter(
                            this@UpsertSourceActivity,
                            android.R.layout.simple_spinner_item,
                            itemsStrings,
                        )
                    spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
                    binding.spoutsSpinner.adapter = spinnerArrayAdapter

                    if (existingSource != null) {
                        initFields(items)
                    }
                } else {
                    handleSpoutFailure()
                }
            } catch (e: NetworkUnavailableException) {
                handleSpoutFailure(networkIssue = true)
            }
        }
    }

    private fun maybeGetDetailsFromIntentSharing(intent: Intent) {
        if (Intent.ACTION_SEND == intent.action && "text/plain" == intent.type) {
            binding.sourceUri.setText(intent.getStringExtra(Intent.EXTRA_TEXT))
            binding.nameInput.setText(intent.getStringExtra(Intent.EXTRA_TITLE))
        }
    }

    private fun mustLoginToAddSource() {
        Toast.makeText(this, getString(R.string.addStringNoUrl), Toast.LENGTH_SHORT).show()
        val i = Intent(this, LoginActivity::class.java)
        startActivity(i)
        finish()
    }

    private fun handleSaveSource() {
        val url = binding.sourceUri.text.toString()

        val sourceDetailsUnavailable =
            title.isEmpty() || url.isEmpty() || mSpoutsValue == null || mSpoutsValue!!.isEmpty()

        when {
            sourceDetailsUnavailable -> {
                Toast.makeText(this, R.string.form_not_complete, Toast.LENGTH_SHORT).show()
            }
            else -> {
                CoroutineScope(Dispatchers.Main).launch {
                    val successfullyAddedSource =
                        if (existingSource != null) {
                            repository.updateSource(
                                existingSource!!.id,
                                binding.nameInput.text.toString(),
                                url,
                                mSpoutsValue!!,
                                binding.tags.text.toString(),
                            )
                        } else {
                            repository.createSource(
                                binding.nameInput.text.toString(),
                                url,
                                mSpoutsValue!!,
                                binding.tags.text.toString(),
                            )
                        }
                    if (successfullyAddedSource) {
                        finish()
                    } else {
                        Toast.makeText(
                            this@UpsertSourceActivity,
                            R.string.cant_create_source,
                            Toast.LENGTH_SHORT,
                        ).show()
                    }
                }
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        repository.unsetSelectedSource()
    }
}
