package edu.byu.support.fragment

import android.graphics.Bitmap
import android.graphics.PorterDuff
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.os.Bundle
import android.os.CountDownTimer
import android.support.v4.content.ContextCompat
import android.support.v7.widget.GridLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.TextView
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.animation.GlideAnimation
import com.bumptech.glide.request.target.SimpleTarget
import edu.byu.support.ByuClickListener
import edu.byu.support.ByuRecyclerView
import edu.byu.support.ByuViewHolder
import edu.byu.support.R
import edu.byu.support.activity.ByuActivity
import edu.byu.support.adapter.ByuRecyclerAdapter
import edu.byu.support.client.cameraFeed.ByuCameraFeedClient
import edu.byu.support.client.cameraFeed.model.CameraFeed
import edu.byu.support.retrofit.ByuSuccessCallback
import kotlinx.android.synthetic.main.camera_feed_cardview.view.*
import kotlinx.android.synthetic.main.camera_feed_layout.view.*
import kotlinx.android.synthetic.main.cameras_fragment_recycler_layout.*
import kotlinx.android.synthetic.main.cameras_fragment_recycler_layout.view.*
import retrofit2.Call
import retrofit2.Response
import java.lang.Exception

/**
 * Created by ahill18 on 2/28/18.
 */
class CamerasGridFragment: ByuRecyclerViewFragment() {

	var expandedCameraView: View? = null

	companion object {
		const val NUM_COLUMNS = 2
		const val GRID_VIEW_SWITCHER_POSITION = 1
		const val CAMERA_FILTER = "camera_filter"
	}

	override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {

		val view = super.onCreateView(inflater, container, R.layout.cameras_fragment_recycler_layout)
		recyclerView.layoutManager = GridLayoutManager(activity, NUM_COLUMNS)
		recyclerView.removeHorizontalLineDivider()

		expandedCameraView = view.camera_feed_full_screen_frame

		val layerDrawable = expandedCameraView?.camera_view_progress_bar?.progressDrawable as LayerDrawable
		val drawable = layerDrawable.getDrawable(2)
		activity?.let { drawable.setColorFilter(ContextCompat.getColor(it, R.color.colorAccent), PorterDuff.Mode.SRC_IN) }

		setAdapter(FeedRecyclerAdapter())

		recyclerView.addOnScrollListener(object: RecyclerView.OnScrollListener() {
			override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
				super.onScrolled(recyclerView, dx, dy)
				updateShowingImages()
			}
		})

		loadCameras()

		return view
	}

	private fun loadCameras() {

		enqueueCall(ByuCameraFeedClient().getApi(activity).availableCameraFeeds, object: ByuSuccessCallback<List<CameraFeed>>(activity as? ByuActivity) {
			override fun onSuccess(call: Call<List<CameraFeed>>, response: Response<List<CameraFeed>>) {

				//Filter out unneeded camera streams through CAMERA_FILTER variable
				val list: List<CameraFeed>? = response.body()?.filter { feed ->
					arguments?.getString(CAMERA_FILTER) == null || feed.category == arguments?.getString(CAMERA_FILTER)
				}

				recyclerView.adapter.setList(ArrayList<RefreshTimerImage>())
				list?.let {
					for ((index, feed) in it.withIndex()) {
						recyclerView.adapter.list.add(RefreshTimerImage(feed, index))
					}
				}
				view?.loading_grid_view_switcher?.displayedChild = GRID_VIEW_SWITCHER_POSITION
				recyclerView.adapter.notifyDataSetChanged()
			}
		})
	}

	fun updateShowingImages() {
		val first = (recyclerView.layoutManager as GridLayoutManager).findFirstVisibleItemPosition()
		val last = (recyclerView.layoutManager as GridLayoutManager).findLastVisibleItemPosition()

		//Check if any of the visible views are waiting to be updated
		if ((recyclerView as ByuRecyclerView).adapter.list.size > 0) {
			for (feed: Any in recyclerView.adapter.list.subList(first, last + 1)) {
				if (feed is RefreshTimerImage && feed.waitingToLoad) {
					feed.loadImage()
				}
			}
		}
	}

	inner class RefreshTimerImage(val feed: CameraFeed, val index: Int) {

		private var timer: CountDownTimer? = null
		var bitmap: Bitmap? = null
		var viewIsShowing = false
		var initialLoad = false
		var millisecondsLeft = (feed.refreshInterval * 1000).toLong()
		var waitingToLoad = false

		fun resumeTimer() {
			timer?.cancel()
			timer = object: CountDownTimer(millisecondsLeft, 100L) {
				override fun onFinish() {
					loadImage()
					millisecondsLeft = (feed.refreshInterval * 1000).toLong()
				}

				override fun onTick(millisecondsLeft: Long) {
					this@RefreshTimerImage.millisecondsLeft = millisecondsLeft
					val progress = ((millisecondsLeft.toDouble() / (feed.refreshInterval * 1000).toDouble()) * 100).toInt()
					recyclerView?.layoutManager?.findViewByPosition(index)?.camera_card_view_frame_layout?.camera_view_progress_bar?.progress = progress
					if (viewIsShowing) {
						expandedCameraView?.camera_view_progress_bar?.progress = progress
					}
				}
			}
			timer?.start()
		}

		fun stopTimer() {
			timer?.cancel()
		}

		fun loadImage() {

			//Glide is used here because it handles recycling the bitmaps and prevents memory leaks
			//Only load image if it is currently visible to the user
			if ((recyclerView?.layoutManager as GridLayoutManager).findFirstVisibleItemPosition() <= index
					&& (recyclerView?.layoutManager as GridLayoutManager).findLastVisibleItemPosition() >= index
					&& userVisibleHint) {
				Glide.with(activity)
						.load(feed.location)
						.asBitmap()
						.diskCacheStrategy(DiskCacheStrategy.NONE)
						.skipMemoryCache(true)
						.into(object: SimpleTarget<Bitmap>() {
							override fun onResourceReady(resource: Bitmap?, glideAnimation: GlideAnimation<in Bitmap>?) {
								if (viewIsShowing) {
									expandedCameraView?.camera_view_image?.setImageBitmap(resource)
								}
								bitmap = resource
								recyclerView.adapter.notifyItemChanged(index)
								resumeTimer()
								waitingToLoad = false
							}

							override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
								//If it fails to load just restart timer with current image and try again when timer finishes
								resumeTimer()
							}
						})
			} else {
				waitingToLoad = true
			}
		}

	}

	inner class FeedRecyclerAdapter: ByuRecyclerAdapter<RefreshTimerImage>(emptyList()) {

		inner class ViewHolder(itemView: View): ByuViewHolder<RefreshTimerImage>(itemView) {

			private val loadingBar: ProgressBar = itemView.camera_card_view_loading_bar
			val textView: TextView = itemView.camera_card_view_frame_layout.camera_view_text
			val image: ImageView = itemView.camera_card_view_frame_layout.camera_view_image

			override fun bind(data: RefreshTimerImage, listener: ByuClickListener<RefreshTimerImage>?) {
				super.bind(data, listener)

				textView.text = data.feed.name
				image.setImageBitmap(data.bitmap)
				image.scaleType = ImageView.ScaleType.CENTER_CROP

				//If the bitmap isn't null, hide the card view loading bar
				data.bitmap?.let { loadingBar.visibility = View.GONE }

				if (!data.initialLoad) {
					data.loadImage()
					data.initialLoad = true
				}

				itemView.setOnClickListener {
					//Show expanded view
					expandedCameraView?.camera_view_image?.setImageBitmap(data.bitmap)
					expandedCameraView?.camera_view_text?.text = data.feed.name
					expandedCameraView?.camera_view_image?.layoutParams?.height = ViewGroup.LayoutParams.WRAP_CONTENT
					expandedCameraView?.visibility = View.VISIBLE
					data.viewIsShowing = true
					camera_feed_full_screen?.setOnClickListener {
						//Hide expanded view
						expandedCameraView?.visibility = View.GONE
						data.viewIsShowing = false
					}
				}
			}

		}

		override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ByuViewHolder<RefreshTimerImage> {
			val view = LayoutInflater.from(parent.context).inflate(R.layout.camera_feed_cardview, parent, false)
			val displayFeed = LayoutInflater.from(parent.context).inflate(R.layout.camera_feed_layout, parent, false)

			val layerDrawable = displayFeed.camera_view_progress_bar?.progressDrawable as LayerDrawable
			val drawable = layerDrawable.getDrawable(2)
			activity?.let { drawable.setColorFilter(ContextCompat.getColor(it, R.color.colorAccent), PorterDuff.Mode.SRC_IN) }

			view.camera_card_view_frame_layout.addView(displayFeed)
			return ViewHolder(view)
		}

	}

	override fun onDestroy() {
		super.onDestroy()
		if (recyclerView.adapter.list is List<*>) {
			for (feed: Any in recyclerView.adapter.list) {
				if (feed is RefreshTimerImage) {
					feed.stopTimer()
				}
			}
		}
	}

}