package org.mosad.teapod.util.adapter

import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import jp.wasabeef.glide.transformations.RoundedCornersTransformation
import org.mosad.teapod.R
import org.mosad.teapod.databinding.ItemEpisodeBinding
import org.mosad.teapod.databinding.ItemEpisodePlayerBinding
import org.mosad.teapod.parser.crunchyroll.Episode
import org.mosad.teapod.parser.crunchyroll.PlayheadObject
import org.mosad.teapod.util.tmdb.TMDBTVEpisode

class EpisodeItemAdapter(
    private val episodes: List<Episode>,
    private val tmdbEpisodes: List<TMDBTVEpisode>?,
    private val playheads: Map<String, PlayheadObject>,
    private val onClickListener: OnClickListener,
    private val viewType: ViewType
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    var currentSelected: Int = -1 // -1, since position should never be < 0

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        return when (viewType) {
            ViewType.PLAYER.ordinal -> {
                PlayerEpisodeViewHolder((ItemEpisodePlayerBinding.inflate(LayoutInflater.from(parent.context), parent, false)))
            }
            else -> {
                // media fragment episode list is default
                EpisodeViewHolder(ItemEpisodeBinding.inflate(LayoutInflater.from(parent.context), parent, false))
            }
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        val episode = episodes[position]
        val playhead = playheads[episode.id]
        val tmdbEpisode = tmdbEpisodes?.getOrNull(position)

        when (holder.itemViewType) {
            ViewType.MEDIA_FRAGMENT.ordinal -> {
                (holder as EpisodeViewHolder).bind(episode, playhead, tmdbEpisode)
            }
            ViewType.PLAYER.ordinal -> {
                (holder as PlayerEpisodeViewHolder).bind(episode, playhead, currentSelected)
            }
        }
    }

    override fun getItemViewType(position: Int): Int {
        return when (viewType) {
            ViewType.MEDIA_FRAGMENT -> ViewType.MEDIA_FRAGMENT.ordinal
            ViewType.PLAYER -> ViewType.PLAYER.ordinal
        }
    }

    override fun getItemCount(): Int {
        return episodes.size
    }

    inner class EpisodeViewHolder(val binding: ItemEpisodeBinding) :
        RecyclerView.ViewHolder(binding.root) {

        fun bind(episode: Episode, playhead: PlayheadObject?, tmdbEpisode: TMDBTVEpisode?) {
            val context = binding.root.context

            val titleText = if (episode.episodeNumber != null) {
                // for tv shows add ep prefix and episode number
                if (episode.isDubbed) {
                    context.getString(R.string.component_episode_title, episode.episode, episode.title)
                } else {
                    context.getString(R.string.component_episode_title_sub, episode.episode, episode.title)
                }
            } else {
                episode.title
            }

            binding.textEpisodeTitle.text = titleText
            binding.textEpisodeDesc.text = episode.description.ifEmpty {
                tmdbEpisode?.overview ?: ""
            }

            if (episode.images.thumbnail[0][0].source.isNotEmpty()) {
                Glide.with(context).load(episode.images.thumbnail[0][0].source)
                    .apply(RequestOptions.placeholderOf(ColorDrawable(Color.DKGRAY)))
                    .apply(RequestOptions.bitmapTransform(RoundedCornersTransformation(10, 0)))
                    .into(binding.imageEpisode)
            }

            // add watched progress
            val playheadProgress = playhead?.playhead?.let {
                ((it.toFloat() / (episode.durationMs / 1000)) * 100).toInt()
            } ?: 0
            binding.progressPlayhead.setProgressCompat(playheadProgress, false)
            binding.progressPlayhead.visibility = if (playheadProgress <= 0)
                View.GONE  else View.VISIBLE

            // add watched icon to episode, if the episode id is present in playheads and fullyWatched
            val watchedImage: Drawable? = if (playhead?.fullyWatched == true) {
                ContextCompat.getDrawable(context, R.drawable.ic_baseline_check_circle_24)
            } else {
                null
            }
            binding.imageWatched.setImageDrawable(watchedImage)

            binding.imageEpisode.setOnClickListener {
                onClickListener.onClick(episode)
            }
        }
    }

    inner class PlayerEpisodeViewHolder(val binding: ItemEpisodePlayerBinding) :
        RecyclerView.ViewHolder(binding.root) {

        // -1, since position should never be < 0
        fun bind(episode: Episode, playhead: PlayheadObject?, currentSelected: Int) {
            val context = binding.root.context

            val titleText = if (episode.episodeNumber != null) {
                // for tv shows add ep prefix and episode number
                if (episode.isDubbed) {
                    context.getString(R.string.component_episode_title, episode.episode, episode.title)
                } else {
                    context.getString(R.string.component_episode_title_sub, episode.episode, episode.title)
                }
            } else {
                episode.title
            }

            binding.textEpisodeTitle2.text = titleText
            binding.textEpisodeDesc2.text = episode.description.ifEmpty { "" }

            if (episode.images.thumbnail[0][0].source.isNotEmpty()) {
                Glide.with(context).load(episode.images.thumbnail[0][0].source)
                    .apply(RequestOptions.bitmapTransform(RoundedCornersTransformation(10, 0)))
                    .into(binding.imageEpisode)
            }

            // add watched progress
            val playheadProgress = playhead?.playhead?.let {
                ((it.toFloat() / (episode.durationMs / 1000)) * 100).toInt()
            } ?: 0
            binding.progressPlayhead.setProgressCompat(playheadProgress, false)
            binding.progressPlayhead.visibility = if (playheadProgress <= 0)
                View.GONE  else View.VISIBLE

            // hide the play icon, if it's the current episode
            binding.imageEpisodePlay.visibility = if (currentSelected == bindingAdapterPosition) {
                View.GONE
            } else {
                View.VISIBLE
            }

            if (currentSelected != bindingAdapterPosition) {
                binding.imageEpisode.setOnClickListener {
                    onClickListener.onClick(episode)
                }
            }
        }
    }

    class OnClickListener(val clickListener: (episode: Episode) -> Unit) {
        fun onClick(episode: Episode) = clickListener(episode)
    }

    enum class ViewType {
        MEDIA_FRAGMENT,
        PLAYER
    }
}