// SPDX-FileCopyrightText: Adam Evyčędo
//
// SPDX-License-Identifier: GPL-3.0-or-later

package xyz.apiote.bimba.czwek.settings

import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.graphics.Color
import android.os.Bundle
import android.util.Log
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.edit
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.core.widget.addTextChangedListener
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.yaml.snakeyaml.error.YAMLException
import xyz.apiote.bimba.czwek.R
import xyz.apiote.bimba.czwek.api.Bimba
import xyz.apiote.bimba.czwek.api.Server
import xyz.apiote.bimba.czwek.api.TrafficFormatException
import xyz.apiote.bimba.czwek.api.getBimba
import xyz.apiote.bimba.czwek.databinding.ActivityServerChooserBinding
import xyz.apiote.bimba.czwek.onboarding.FirstRunActivity
import xyz.apiote.bimba.czwek.settings.feeds.FeedChooserActivity

class ServerChooserActivity : AppCompatActivity() {
	companion object {
		const val PARAM_SIMPLE = "simple"
		const val IN_FEEDS_TRANSACTION = "inFeedsTransaction"
		const val PREFERENCES_NAME = "shp"
		fun getIntent(context: Context, simple: Boolean) = Intent(context, ServerChooserActivity::class.java).apply {
				putExtra(PARAM_SIMPLE, simple)
		}
	}

	private var _binding: ActivityServerChooserBinding? = null
	private val binding get() = _binding!!

	private val activityLauncher =
		registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
			if (!preferences.getBoolean(IN_FEEDS_TRANSACTION, true)) {
				finish()
			}
		}

	private lateinit var preferences: SharedPreferences

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

		preferences = getSharedPreferences(PREFERENCES_NAME, MODE_PRIVATE)

		if (intent.getBooleanExtra(PARAM_SIMPLE, false)) {
			setServer(Server.DEFAULT, "")
			checkServer(true)
		} else {
			_binding = ActivityServerChooserBinding.inflate(layoutInflater)
			setContentView(binding.root)

			ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, windowInsets ->
				val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
				v.updatePadding(right = insets.right, left = insets.left, top = insets.top)
				windowInsets
			}

			preferences.edit(true) {
				putBoolean(IN_FEEDS_TRANSACTION, true)
			}

			if (preferences.getBoolean("shibboleet", false)) {
				binding.button.setBackgroundColor(Color.rgb(35, 93, 121))
				binding.button.setTextColor(Color.WHITE)
			}

			binding.button.isEnabled = false
			binding.serverField.editText!!.addTextChangedListener { editable ->
				binding.button.isEnabled = !editable.isNullOrBlank()
			}

			if (!FirstRunActivity.getFirstRun(this)) {
				Server.get(this).let { server ->
					binding.serverField.editText!!.setText(server.host)
					binding.tokenField.editText!!.setText(server.token)
				}
			}

			binding.button.setOnClickListener {
				when (binding.serverField.editText!!.text.toString()) {
					":shibboleet" -> {
						binding.button.setBackgroundColor(Color.rgb(35, 93, 121))
						binding.button.setTextColor(Color.WHITE)
						preferences.edit(true) {
							putBoolean("shibboleet", true)
						}
						if (!FirstRunActivity.getFirstRun(this)) {
							Server.get(this).let { server ->
								binding.serverField.editText!!.setText(server.host)
								binding.tokenField.editText!!.setText(server.token)
							}
						}
					}

					";shibboleet" -> {
						_binding = ActivityServerChooserBinding.inflate(layoutInflater)
						setContentView(binding.root)
						preferences.edit(true) {
							putBoolean("shibboleet", false)
						}
						if (!FirstRunActivity.getFirstRun(this)) {
							Server.get(this).let { server ->
								binding.serverField.editText!!.setText(server.host)
								binding.tokenField.editText!!.setText(server.token)
							}
						}
					}

					else -> {
						setServer(
							binding.serverField.editText!!.text.toString(),
							binding.tokenField.editText!!.text.toString()
						)
						checkServer(false)
					}
				}
			}
		}
	}

	private fun showDialog(
		title: Int, description: Int, icon: Int, onPositive: (() -> Unit)?
	) {
		MaterialAlertDialogBuilder(this).setIcon(AppCompatResources.getDrawable(this, icon))
			.setTitle(getString(title)).setMessage(getString(description))
			.setNegativeButton(R.string.cancel) { _, _ -> }.apply {
				if (onPositive != null) {
					setPositiveButton(R.string.continue_) { _, _ ->
						onPositive()
					}
				}
			}.show()
	}

	private fun checkServer(isSimple: Boolean) {
		MainScope().launch {
			val result = getBimba(this@ServerChooserActivity, Server.get(this@ServerChooserActivity))
			if (result.error != null) {
				showDialog(R.string.error, result.error.stringResource, result.error.imageResource, null)
				Log.w(
					"ServerChooser", "${result.error.statusCode}, ${getString(result.error.stringResource)}"
				)
				return@launch
			}
			val bimba = try {
				withContext(Dispatchers.IO) {
					Bimba.unmarshal(result.stream!!)
				}
			} catch (e: YAMLException) {
				Log.w("ServerChooser", e.message ?: "YAML error")
				showDialog(R.string.error, R.string.error_traffic_spec, R.drawable.error_server, null)
				return@launch
			} catch (e: TrafficFormatException) {
				Log.w("ServerChooser", e.message)
				showDialog(R.string.error, R.string.error_traffic_spec, R.drawable.error_server, null)
				return@launch
			}

			if (preferences.getBoolean("shibboleet", false)) {
				val validServers = bimba.servers.filter { !it.getOrDefault("url", null).isNullOrBlank() }
				val servers = validServers.toTypedArray()
				MaterialAlertDialogBuilder(this@ServerChooserActivity)
					.setTitle(R.string.choose_server)
					.setItems(servers.map { it["description"] }.toTypedArray()) { _, i ->
						updateServer(servers[i]["url"].toString())
						moveOn(bimba, false)
					}
					.show()
				return@launch
			}

			updateServer(bimba.servers[0]["url"]!!)
			moveOn(bimba, isSimple)
			return@launch
		}
	}

	private fun moveOn(bimba: Bimba, isSimple: Boolean) {
		val token = preferences.getString(Server.TOKEN_KEY, "")

		if (bimba.isPrivate() && token == "") {
			showDialog(R.string.error, R.string.server_private_question, R.drawable.error_sec, null)
			return
		}
		if (bimba.isRateLimited() && token == "" && !isSimple) {
			showDialog(
				R.string.rate_limit, R.string.server_rate_limited_question, R.drawable.error_limit
			) {
				runFeedsActivity()
			}
			return
		}
		runFeedsActivity()
	}

	private fun setServer(hostname: String, token: String) {
		preferences.edit(true) {
			putString(Server.HOST_KEY, hostname)
			putString(Server.TOKEN_KEY, token)
		}
	}

	private fun updateServer(apiPath: String) {
		preferences.edit(true) {
			putString(Server.API_PATH_KEY, apiPath)
		}
	}

	private fun runFeedsActivity() {
		activityLauncher.launch(Intent(this, FeedChooserActivity::class.java))
		if (intent.getBooleanExtra(PARAM_SIMPLE, false)) {
			finish()
		}
	}
}