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

package xyz.apiote.bimba.czwek.dashboard.ui.journey

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.RectF
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Bundle
import android.text.Spanned
import android.text.style.ImageSpan
import android.util.Log
import android.view.LayoutInflater
import android.view.MotionEvent.ACTION_UP
import android.view.View
import android.view.ViewGroup
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipDrawable
import com.google.android.material.textfield.TextInputEditText
import xyz.apiote.bimba.czwek.R
import xyz.apiote.bimba.czwek.dashboard.MainActivity
import xyz.apiote.bimba.czwek.databinding.FragmentJourneyBinding
import xyz.apiote.bimba.czwek.dpToPixelI
import xyz.apiote.bimba.czwek.journeys.JourneysActivity
import xyz.apiote.bimba.czwek.repo.Place

class JourneyFragment : Fragment(), LocationListener {

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

	private lateinit var dashboard: MainActivity
	private var hereChipRequester: Chip? = null

	override fun onCreateView(
		inflater: LayoutInflater,
		container: ViewGroup?,
		savedInstanceState: Bundle?
	): View {
		val journeyViewModel =
			ViewModelProvider(this)[JourneyViewModel::class.java]

		// TODO separate layout: two columns for horizontal

		_binding = FragmentJourneyBinding.inflate(inflater, container, false)
		val root: View = binding.root

		ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets ->
			val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
			binding.originInput.updatePadding(left = insets.left, right = insets.right)
			binding.originInput.updateLayoutParams<ViewGroup.MarginLayoutParams> {
				topMargin = insets.top + dpToPixelI(16f)
				windowInsets.displayCutout?.safeInsetLeft?.let {
					leftMargin = it + dpToPixelI(16f)
				}
				windowInsets.displayCutout?.safeInsetRight?.let {
					rightMargin = it + dpToPixelI(16f)
				}
			}
			binding.originSuggestions.updatePadding(left = insets.left, right = insets.right)
			binding.originSuggestions.updateLayoutParams<ViewGroup.MarginLayoutParams> {
				windowInsets.displayCutout?.safeInsetLeft?.let {
					leftMargin = it + dpToPixelI(16f)
				}
				windowInsets.displayCutout?.safeInsetRight?.let {
					rightMargin = it + dpToPixelI(16f)
				}
			}
			binding.destinationInput.updatePadding(left = insets.left, right = insets.right)
			binding.destinationInput.updateLayoutParams<ViewGroup.MarginLayoutParams> {
				windowInsets.displayCutout?.safeInsetLeft?.let {
					leftMargin = it + dpToPixelI(16f)
				}
				windowInsets.displayCutout?.safeInsetRight?.let {
					rightMargin = it + dpToPixelI(16f)
				}
			}
			binding.destinationSuggestions.updatePadding(left = insets.left, right = insets.right)
			binding.destinationSuggestions.updateLayoutParams<ViewGroup.MarginLayoutParams> {
				windowInsets.displayCutout?.safeInsetLeft?.let {
					leftMargin = it + dpToPixelI(16f)
				}
				windowInsets.displayCutout?.safeInsetRight?.let {
					rightMargin = it + dpToPixelI(16f)
				}
			}
			windowInsets
		}

		dashboard = activity as MainActivity

		dashboard.hideBadge()
		dashboard.viewModel.origin.let {
			chipifyOrigin(it.value)
		}

		dashboard.viewModel.destination.let {
			chipifyDestination(it.value)
		}

		binding.originChipHere.setOnClickListener {
			setHere(it as Chip)
		}

		binding.destinationChipHere.setOnClickListener {
			setHere(it as Chip)
		}

		binding.goButton.isEnabled =
			dashboard.viewModel.origin.value != null && dashboard.viewModel.destination.value != null

		binding.goButton.setOnClickListener {
			val intent = JourneysActivity.getIntent(
				requireContext(),
				dashboard.viewModel.origin.value!!,
				dashboard.viewModel.destination.value!!
			)
			startActivity(intent)
		}

		dashboard.viewModel.origin.observe(viewLifecycleOwner) {
			chipifyOrigin(it)
		}

		dashboard.viewModel.destination.observe(viewLifecycleOwner) {
			chipifyDestination(it)
		}

		// TODO listen to text changes
		// TODO search by text input

		return root
	}

	private fun chipifyOrigin(place: Place?) {
		if (place != null) {
			chipify(place, binding.origin)
		}
	}

	private fun chipifyDestination(place: Place?) {
		if (place != null) {
			chipify(place, binding.destination)
		}
	}

	private fun chipify(place: Place, textView: TextInputEditText) {
		var chip: ChipDrawable? = ChipDrawable.createFromResource(requireContext(), R.xml.journey_chip)
		val text = place.shortString()
		textView.setText(text)
		chip!!.text = text
		chip.setBounds(0, 0, chip.intrinsicWidth, chip.intrinsicHeight)
		val span = ImageSpan(chip)
		textView.text?.setSpan(span, 0, text.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
		@SuppressLint("ClickableViewAccessibility")
		textView.setOnTouchListener { v, e ->
			v.performClick()
			if (chip != null) {
				val chipContentRect = RectF()
				val chipCloseRect = RectF()
				chip!!.getChipTouchBounds(chipContentRect)
				chip!!.getCloseIconTouchBounds(chipCloseRect)
				if (e.x > textView.totalPaddingLeft && e.x < textView.totalPaddingLeft + chipContentRect.right
					&& e.y > textView.totalPaddingTop && e.y < textView.totalPaddingTop + chipContentRect.bottom
				) {
					if (e.action == ACTION_UP) {
						// TODO popup
						Log.i("Touch", "content")
					}
					true
				} else if (e.x > textView.totalPaddingLeft + chipContentRect.right && e.x < textView.totalPaddingLeft + chipContentRect.right + chipCloseRect.right
					&& e.y > textView.totalPaddingTop && e.y < textView.totalPaddingTop + chipCloseRect.bottom
				) {
					if (e.action == ACTION_UP) {
						textView.setText("")
						chip = null
					}
					true
				} else {
					false
				}
			} else {
				false
			}
		}
	}

	private fun setHere(v: Chip) {
		hereChipRequester = v
		if (dashboard.onGpsClicked(this)) {
			try {
				val locationManager =
					requireContext().getSystemService(Context.LOCATION_SERVICE) as LocationManager
				locationManager.requestLocationUpdates(
					LocationManager.GPS_PROVIDER, 1000 * 60 * 10, 100f, this
				)
				locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER)
					?.let { onLocationChanged(it) }
			} catch (_: SecurityException) {
				Log.wtf(
					"locate",
					"this shouldn’t happen because we don’t run this without location permission"
				)
			}
		}
	}

	override fun onDestroyView() {
		super.onDestroyView()
		_binding = null
	}

	override fun onLocationChanged(location: Location) {
		when (hereChipRequester?.id) {
			R.id.origin_chip_here ->
				dashboard.viewModel.setOrigin(Place(location.latitude, location.longitude))

			R.id.destination_chip_here ->
				dashboard.viewModel.setDestination(Place(location.latitude, location.longitude))
		}
		hereChipRequester = null
	}
}