package net.pokeranalytics.android.ui.fragment

import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.os.Bundle
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.style.TypefaceSpan
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.Toast
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.children
import androidx.core.view.setMargins
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import androidx.viewpager.widget.ViewPager
import com.android.billingclient.api.BillingClient
import com.android.billingclient.api.Purchase
import com.android.billingclient.api.SkuDetails
import com.android.billingclient.api.SkuDetailsResponseListener
import kotlinx.android.synthetic.main.fragment_subscription.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.fragment.components.ScreenSlidePageFragment
import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.billing.AppGuard
import net.pokeranalytics.android.util.billing.IAPProducts
import net.pokeranalytics.android.util.billing.PurchaseDelegate
import java.lang.ref.WeakReference
import java.time.Period

class SubscriptionFragment : PokerAnalyticsFragment(), SkuDetailsResponseListener, PurchaseDelegate, ViewPager.OnPageChangeListener {

	companion object {
		val parallax: Float = 64f.px
	}

	private var pagerAdapter: ScreenSlidePagerAdapter? = null
	private var selectedProduct: SkuDetails? = null

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

		this.showLoader(R.string.loading_please_wait)
		if (!AppGuard.requestProducts(this)) {
			this.hideLoader()
			Toast.makeText(requireContext(), R.string.billingclient_unavailable, Toast.LENGTH_LONG).show()
		}
	}

	override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
		return inflater.inflate(R.layout.fragment_subscription, container, false)
	}

	override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
		super.onViewCreated(view, savedInstanceState)

		initUI()
	}

	private fun initUI() {

		val upgradeString = requireContext().getString(R.string.pro_upgrade)

		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {

			val ssb = SpannableStringBuilder(upgradeString)

			val indexOfLastSpace = upgradeString.lastIndexOf(" ")
			val end = upgradeString.chars().count().toInt()

			val lightTypeFace = ResourcesCompat.getFont(requireContext(), R.font.roboto_light)
			val boldTypeFace = ResourcesCompat.getFont(requireContext(), R.font.roboto_bold)

			if (lightTypeFace != null && boldTypeFace != null) {
				ssb.setSpan(TypefaceSpan(lightTypeFace), 0, indexOfLastSpace, Spanned.SPAN_EXCLUSIVE_INCLUSIVE)
				ssb.setSpan(TypefaceSpan(boldTypeFace), indexOfLastSpace, end, Spanned.SPAN_EXCLUSIVE_INCLUSIVE)
			}

			this.title.text = ssb

		} else {
			this.title.text = upgradeString
		}

		// Pager

		// The pager adapter, which provides the pages to the view pager widget.
		this.pagerAdapter = ScreenSlidePagerAdapter(requireFragmentManager())
		this.pager.adapter = pagerAdapter
		this.pager.addOnPageChangeListener(this)

		this.purchase.isEnabled = false
		this.purchase.setOnClickListener {

			this.selectedProduct?.let {
				AppGuard.initiatePurchase(this.requireActivity(), it, this)
			} ?: run {
				throw IllegalStateException("Attempt to initiate purchase while no product has been chosen")
			}
		}

		val count = this.pager.adapter?.count ?: 0
		for (i in 1..count) {
			val view = View(requireContext())
			view.background = requireContext().getDrawable(R.drawable.circle_green)
			val layoutParam = LinearLayout.LayoutParams(10.px, 10.px)
			layoutParam.setMargins(6.px)
			this.pageIndicator.addView(view, layoutParam)
		}

		this.updatePagerIndicators(0)

	}

	/**
	 * A simple pager adapter that represents 5 ScreenSlidePageFragment objects, in
	 * sequence.
	 */
	private inner class ScreenSlidePagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) {

		private var fragments: HashMap<Int, WeakReference<ScreenSlidePageFragment>> = HashMap()

		private inner class FeatureDescriptor(var iconResId: Int, var titleResId: Int, var descResId: Int)

		override fun instantiateItem(container: ViewGroup, position: Int): Any {
			val fragment = super.instantiateItem(container, position) as ScreenSlidePageFragment
			fragments[position] = WeakReference(fragment)
			return super.instantiateItem(container, position)
		}

		private val dataSource: List<FeatureDescriptor> = listOf(
			FeatureDescriptor(R.drawable.ic_baseline_all_inclusive, R.string.f_unlimited, R.string.f_unlimited_desc),
			FeatureDescriptor(R.drawable.ic_baseline_wifi_off, R.string.f_offline, R.string.f_offline_desc),
			FeatureDescriptor(R.drawable.ic_baseline_vpn_key, R.string.f_privacy, R.string.f_privacy_desc),
			FeatureDescriptor(R.drawable.ic_baseline_email, R.string.f_support, R.string.f_support_desc)
		)

		override fun getCount(): Int = this.dataSource.size
		override fun getItem(position: Int): Fragment {
			val d = this.dataSource[position]
			return ScreenSlidePageFragment(d.iconResId, d.titleResId, d.descResId)
		}

		/**
		 * Return the fragment at [position]
		 */
		fun getFragment(position: Int): ScreenSlidePageFragment? {
			if (fragments.contains(position)) {
				return fragments[position]?.get()
			}
			return null
		}
	}

	// SkuDetailsResponseListener
	override fun onSkuDetailsResponse(responseCode: Int, skuDetailsList: MutableList<SkuDetails>?) {
		if (responseCode == BillingClient.BillingResponse.OK && skuDetailsList != null) {
			this.hideLoader()
			selectedProduct = skuDetailsList.first { it.sku == IAPProducts.PRO.identifier }
			updateUI()
		}
	}

	private fun updateUI() {
		this.selectedProduct?.let {
			this.purchase.isEnabled = true
			val perYearString = requireContext().getString(R.string.year_subscription)
			val formattedPrice = it.price + " / " + perYearString
			this.price.text = formattedPrice

			var freeTrialDays = 30 // initial, should be more, no less
			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
				val p = Period.parse(it.freeTrialPeriod)
				freeTrialDays = p.days
			}
			val formattedFreeTrial =
				"$freeTrialDays " + requireContext().getString(R.string.days) + " " + requireContext().getString(R.string.free_trial)
			this.freetrial.text = formattedFreeTrial
		}
	}

	// PurchaseDelegate

	override fun purchaseDidSucceed(purchase: Purchase) {

		// record purchase in preferences for troubleshooting / verification
		val purchaseInfos = listOf(purchase.sku, purchase.orderId, purchase.purchaseToken)
		Preferences.setString(Preferences.Keys.LATEST_PURCHASE, purchaseInfos.joinToString("/"), requireContext())

		this.activity?.finish()
	}

	// OnPageChangeListener

	override fun onPageScrollStateChanged(state: Int) {}

	override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
		pagerAdapter?.getFragment(position)?.let {
			it.updateViewsPosition(-positionOffset * parallax)
		}
		pagerAdapter?.getFragment(position + 1)?.let {
			it.updateViewsPosition((1 - positionOffset) * parallax)
		}
	}

	override fun onPageSelected(position: Int) {
		updatePagerIndicators(position)
	}

	private fun updatePagerIndicators(position: Int) {
		this.pageIndicator.children.forEachIndexed { index, view ->
			val drawable = view.background
			when (drawable) {
				is GradientDrawable -> {
					val color = if (position == index) R.color.white else R.color.quantum_grey
					drawable.setColor(requireContext().getColor(color))
				}
				else -> {
				}
			}
		}
	}

}