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

package xyz.apiote.bimba.czwek.dashboard

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.TypedArray
import android.os.Build
import android.os.Bundle
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.content.edit
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.get
import androidx.core.view.updatePadding
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.setupWithNavController
import androidx.preference.PreferenceManager
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.openlocationcode.OpenLocationCode
import xyz.apiote.bimba.czwek.AboutActivity
import xyz.apiote.bimba.czwek.R
import xyz.apiote.bimba.czwek.dashboard.ui.home.HomeFragment
import xyz.apiote.bimba.czwek.dashboard.ui.journey.JourneyFragment
import xyz.apiote.bimba.czwek.dashboard.ui.map.MapFragment
import xyz.apiote.bimba.czwek.databinding.ActivityMainBinding
import xyz.apiote.bimba.czwek.onboarding.FirstRunActivity
import xyz.apiote.bimba.czwek.search.ResultsActivity
import xyz.apiote.bimba.czwek.settings.DownloadCitiesWorker
import xyz.apiote.bimba.czwek.settings.ServerChooserActivity
import xyz.apiote.bimba.czwek.settings.SettingsActivity
import xyz.apiote.bimba.czwek.settings.feeds.FeedChooserActivity


class MainActivity : AppCompatActivity() {
	private lateinit var binding: ActivityMainBinding
	private lateinit var locationPermissionRequest: ActivityResultLauncher<Array<String>>

	private lateinit var permissionAsker: Fragment
	private var locationPermissionDialogShown = false
	private var lastFragment: Fragment? = null
	lateinit var viewModel: DashboardViewModel

	override fun onCreate(savedInstanceState: Bundle?) {
		enableEdgeToEdge()
		super.onCreate(savedInstanceState)
		binding = ActivityMainBinding.inflate(layoutInflater)
		setContentView(binding.root)

		viewModel = ViewModelProvider(this)[DashboardViewModel::class.java]

		FirstRunActivity.setFirstRunDone(this)

		ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets ->
			val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
			val l = windowInsets.displayCutout?.safeInsetLeft?.takeIf { it > 0 } ?: insets.left
			binding.navigationDrawer.updatePadding(left = l)
			windowInsets
		}

		supportFragmentManager.registerFragmentLifecycleCallbacks(
			object : FragmentLifecycleCallbacks() {
				override fun onFragmentViewCreated(
					fm: FragmentManager, f: Fragment, v: View, savedInstanceState: Bundle?
				) {
					setNavbarIcons(f)
					super.onFragmentViewCreated(fm, f, v, savedInstanceState)
				}
			}, true
		)

		val onBackPressedCallback =
			object : OnBackPressedCallback(binding.container.isDrawerOpen(binding.navigationDrawer)) {
				override fun handleOnBackPressed() {
					binding.container.closeDrawer(binding.navigationDrawer)
				}
			}
		onBackPressedDispatcher.addCallback(onBackPressedCallback)

		binding.container.addDrawerListener(object : DrawerListener {
			override fun onDrawerSlide(drawerView: View, slideOffset: Float) {}

			override fun onDrawerOpened(drawerView: View) {
				onBackPressedCallback.isEnabled = true
			}

			override fun onDrawerClosed(drawerView: View) {
				onBackPressedCallback.isEnabled = false
			}

			override fun onDrawerStateChanged(newState: Int) {}
		})

		binding.navigationDrawer.setNavigationItemSelectedListener {
			when (it.itemId) {
				R.id.drawer_servers -> {
					startActivity(Intent(this, ServerChooserActivity::class.java))
				}

				R.id.drawer_cities -> {
					startActivity(Intent(this, FeedChooserActivity::class.java))
				}

				R.id.drawer_settings -> {
					startActivity(Intent(this, SettingsActivity::class.java))
				}

				R.id.drawer_about -> {
					startActivity(Intent(this, AboutActivity::class.java))
				}
			}
			false
		}

		val navView: BottomNavigationView = binding.bottomNavigation
		val navHostFragment =
			supportFragmentManager.findFragmentById(R.id.nav_host_fragment_activity_main) as NavHostFragment
		val navController = navHostFragment.navController
		navView.setupWithNavController(navController)

		locationPermissionRequest = registerForActivityResult(
			ActivityResultContracts.RequestMultiplePermissions()
		) { permissions ->
			when {
				permissions[Manifest.permission.ACCESS_FINE_LOCATION] ?: false ||
					permissions[Manifest.permission.ACCESS_COARSE_LOCATION] ?: false -> {
					when (permissionAsker) {
						is HomeFragment -> {
							showResults(ResultsActivity.Mode.MODE_LOCATION)
						}

						is MapFragment -> {
							(permissionAsker as MapFragment).showLocation()
						}
					}
				}

				else -> {
					if (locationPermissionDialogShown) {
						return@registerForActivityResult
					}
					MaterialAlertDialogBuilder(this).setIcon(
						AppCompatResources.getDrawable(
							this,
							R.drawable.error_gps
						)
					)
						.setTitle(getString(R.string.no_location_access))
						.setMessage(getString(R.string.no_location_message))
						.setPositiveButton(R.string.ok) { _, _ -> }
						.show()
					locationPermissionDialogShown = true
				}
			}
		}

		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
			val notificationPermissionAsked =
				PreferenceManager.getDefaultSharedPreferences(this).getBoolean(
					NOTIFICATION_PERMISSION_ASKED, false
				)
			if (ActivityCompat.checkSelfPermission(
					this,
					Manifest.permission.POST_NOTIFICATIONS
				) != PackageManager.PERMISSION_GRANTED && !notificationPermissionAsked
			) {
				requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), 1)
				PreferenceManager.getDefaultSharedPreferences(this).edit {
					putBoolean(NOTIFICATION_PERMISSION_ASKED, true)
				}
			}
		}
	}

	fun onNavigationClicked() {
		if (binding.container.isDrawerOpen(binding.navigationDrawer)) {
			binding.container.closeDrawer(binding.navigationDrawer)
		} else {
			binding.container.openDrawer(binding.navigationDrawer)
		}
	}

	fun onGpsClicked(fragment: Fragment): Boolean {
		when (PackageManager.PERMISSION_GRANTED) {
			ContextCompat.checkSelfPermission(
				this,
				Manifest.permission.ACCESS_COARSE_LOCATION
			) -> {
				when (fragment) {
					is HomeFragment -> {
						showResults(ResultsActivity.Mode.MODE_LOCATION)
					}

					is MapFragment -> {
						fragment.showLocation()
					}

					is JourneyFragment -> {

					}
				}
				return true
			}

			else -> {
				permissionAsker = fragment
				locationPermissionRequest.launch(
					arrayOf(
						Manifest.permission.ACCESS_FINE_LOCATION,
						Manifest.permission.ACCESS_COARSE_LOCATION
					)
				)
				return false
			}
		}
	}

	fun onSearchClicked(text: CharSequence?) {
		if (OpenLocationCode.isValidCode(text.toString())) {
			val olc = OpenLocationCode(text.toString())
			if (!olc.isFull) {
				showResults(ResultsActivity.Mode.MODE_SHORT_CODE_LOCATION, text.toString())
			} else {
				val area = olc.decode()
				showResults(olc.code, area.centerLatitude, area.centerLongitude)
			}
		} else if (OpenLocationCode.isValidCode(
				text.toString().trim().split(" ").first().trim(',').trim()
			)
		) {
			if (PreferenceManager.getDefaultSharedPreferences(applicationContext)
					.getLong(DownloadCitiesWorker.LAST_UPDATE_KEY, -1) < 0
			) {
				if (!PreferenceManager.getDefaultSharedPreferences(applicationContext)
						.getBoolean(NO_GEOCODING_DATA_SHOWN, false)
				) {
					MaterialAlertDialogBuilder(this)
						.setIcon(R.drawable.geocoding)
						.setTitle(R.string.no_geocoding_data)
						.setMessage(R.string.no_geocoding_data_description)
						.setPositiveButton(R.string.ok) { _, _ ->
							showResults(
								ResultsActivity.Mode.MODE_SEARCH,
								text.toString()
							)
						}
						.show()
					PreferenceManager.getDefaultSharedPreferences(applicationContext).edit {
						putBoolean(NO_GEOCODING_DATA_SHOWN, true)
					}
				}
			} else {
				showResults(ResultsActivity.Mode.MODE_SHORT_CODE, text.toString())
			}
		} else {
			showResults(ResultsActivity.Mode.MODE_SEARCH, text.toString())
		}
	}

	private fun showResults(query: String, centerLatitude: Double, centerLongitude: Double) {
		/* todo [3.2] (ux,low) animation
			https://developer.android.com/guide/fragments/animate
			https://github.com/raheemadamboev/fab-explosion-animation-app
		*/
		startActivity(
			ResultsActivity.getIntent(
				this,
				ResultsActivity.Mode.MODE_POSITION,
				query,
				centerLatitude,
				centerLongitude
			)
		)
	}

	private fun showResults(mode: ResultsActivity.Mode, query: String = "") {
		/* todo [3.2] (ux,low) animation
			https://developer.android.com/guide/fragments/animate
			https://github.com/raheemadamboev/fab-explosion-animation-app
		*/
		startActivity(ResultsActivity.getIntent(this, mode, query))
	}

	fun showBadge(complete: Boolean = false) {
		val colourID = if (complete) {
			com.google.android.material.R.attr.colorPrimary
		} else {
			com.google.android.material.R.attr.colorOnSurfaceVariant
		}
		val badge = binding.bottomNavigation.getOrCreateBadge(R.id.navigation_journey)
		val a: TypedArray = theme.obtainStyledAttributes(
			R.style.Theme_Bimba, intArrayOf(colourID)
		)
		val colour = a.getColor(0, 0)
		a.recycle()
		badge.backgroundColor = colour
		badge.isVisible = true
	}

	fun hideBadge() {
		val badge = binding.bottomNavigation.getBadge(R.id.navigation_journey)
		badge?.isVisible = false
	}

	private fun setNavbarIcons(f: Fragment?) {
		binding.bottomNavigation.menu[2].setIcon(R.drawable.journey_outline)
		binding.bottomNavigation.menu[1].setIcon(R.drawable.home_outline)
		binding.bottomNavigation.menu[0].setIcon(R.drawable.map_outline)
		when (f) {
			is HomeFragment -> {
				binding.bottomNavigation.menu[1].setIcon(R.drawable.home_black)
				lastFragment = f
			}

			is JourneyFragment -> {
				binding.bottomNavigation.menu[2].setIcon(R.drawable.journey_black)
				lastFragment = f
			}

			is MapFragment -> {
				binding.bottomNavigation.menu[0].setIcon(R.drawable.map_black)
				lastFragment = f
			}

			null -> {
				binding.bottomNavigation.menu[1].setIcon(R.drawable.home_black)
			}

			else -> {
				setNavbarIcons(lastFragment)
			}
		}
	}

	companion object {
		const val NOTIFICATION_PERMISSION_ASKED = "notificationPermissionAsked"
		const val NO_GEOCODING_DATA_SHOWN = "no_geocoding_data_shown"
	}
}
