/**
 * Teapod
 *
 * Copyright 2020-2022  <seil0@mosad.xyz>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 *
 */

package org.mosad.teapod.ui.activity.main.fragments

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.children
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.bumptech.glide.Glide
import com.facebook.shimmer.ShimmerFrameLayout
import kotlinx.coroutines.launch
import org.mosad.teapod.R
import org.mosad.teapod.databinding.FragmentHomeBinding
import org.mosad.teapod.ui.activity.main.viewmodel.HomeViewModel
import org.mosad.teapod.util.adapter.MediaEpisodeListAdapter
import org.mosad.teapod.util.adapter.MediaItemListAdapter
import org.mosad.teapod.util.playerIntent
import org.mosad.teapod.util.setDrawableTop
import org.mosad.teapod.util.showFragment
import org.mosad.teapod.util.toItemMediaList

class HomeFragment : Fragment() {

    private val classTag = javaClass.name
    private val model: HomeViewModel by viewModels()
    private lateinit var binding: FragmentHomeBinding

    private val itemOffset = 21

    private val playerResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
        model.updateUpNextItems()
    }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        binding = FragmentHomeBinding.inflate(inflater, container, false)
        return binding.root
    }

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

        binding.recyclerUpNext.adapter = MediaEpisodeListAdapter(
            MediaEpisodeListAdapter.OnClickListener {
                playerResult.launch(playerIntent(it.panel.episodeMetadata.seasonId, it.panel.id))
            },
            itemOffset
        )

        binding.recyclerWatchlist.adapter = MediaItemListAdapter(
            MediaItemListAdapter.OnClickListener {
                activity?.showFragment(MediaFragment(it.id))
            },
            itemOffset
        )

        binding.recyclerRecommendations.adapter = MediaItemListAdapter(
            MediaItemListAdapter.OnClickListener {
                activity?.showFragment(MediaFragment(it.id))
            },
            itemOffset
        )

        binding.recyclerNewTitles.adapter = MediaItemListAdapter(
            MediaItemListAdapter.OnClickListener {
                activity?.showFragment(MediaFragment(it.id))
            },
            itemOffset
        )

        binding.recyclerTopTen.adapter = MediaItemListAdapter(
            MediaItemListAdapter.OnClickListener {
                activity?.showFragment(MediaFragment(it.id))
            },
            itemOffset
        )

        binding.textHighlightMyList.setOnClickListener {
            model.toggleHighlightWatchlist()

            // disable the watchlist button until the result has been loaded
            binding.textHighlightMyList.isClickable = false
            // TODO since this might take a few seconds show a loading animation for the watchlist button
        }

        // set the shimmer items size as it's depending on the screen size
        setShimmerLayoutItemSize(binding.shimmerLayoutUpNext)
        setShimmerLayoutItemSize(binding.shimmerLayoutWatchlist)
        setShimmerLayoutItemSize(binding.shimmerLayoutRecommendations)
        setShimmerLayoutItemSize(binding.shimmerLayoutNewTitles)
        setShimmerLayoutItemSize(binding.shimmerLayoutTopTen)

        viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                model.onUiState(viewLifecycleOwner.lifecycleScope) { uiState ->
                    when (uiState) {
                        is HomeViewModel.UiState.Normal -> bindUiStateNormal(uiState)
                        is HomeViewModel.UiState.Loading -> bindUiStateLoading()
                        is HomeViewModel.UiState.Error -> bindUiStateError(uiState)
                    }
                }
            }
        }
    }

    private fun bindUiStateNormal(uiState: HomeViewModel.UiState.Normal) {
        val adapterUpNext = binding.recyclerUpNext.adapter as MediaEpisodeListAdapter
        adapterUpNext.submitList(uiState.upNextItems.filter { !it.fullyWatched })

        val adapterWatchlist = binding.recyclerWatchlist.adapter as MediaItemListAdapter
        adapterWatchlist.submitList(uiState.watchlistItems.toItemMediaList())

        val adapterRecommendations = binding.recyclerRecommendations.adapter as MediaItemListAdapter
        adapterRecommendations.submitList(uiState.recommendationsItems.toItemMediaList())

        val adapterNewTitles = binding.recyclerNewTitles.adapter as MediaItemListAdapter
        adapterNewTitles.submitList(uiState.recentlyAddedItems.toItemMediaList())

        val adapterTopTen = binding.recyclerTopTen.adapter as MediaItemListAdapter
        adapterTopTen.submitList(uiState.topTenItems.toItemMediaList())

        // highlight item
        binding.textHighlightTitle.text = uiState.highlightItem.title
        Glide.with(requireContext()).load(uiState.highlightItem.images.poster_wide[0][3].source)
            .into(binding.imageHighlight)

        val iconHighlightWatchlist = if (uiState.highlightIsWatchlist) {
            R.drawable.ic_baseline_check_24
        } else {
            R.drawable.ic_baseline_add_24
        }
        binding.textHighlightMyList.setDrawableTop(iconHighlightWatchlist)
        binding.textHighlightMyList.isClickable = true

        binding.textHighlightInfo.setOnClickListener {
            activity?.showFragment(MediaFragment(uiState.highlightItem.id))
        }

        binding.buttonPlayHighlight.setOnClickListener {
            val panel = uiState.highlightItemUpNext.panel
            playerResult.launch(playerIntent(panel.episodeMetadata.seasonId, panel.id))
        }

        // disable the shimmer effect
        disableShimmer()

        // make highlights layout visible again
        binding.linearHighlight.isVisible = true
    }

    private fun bindUiStateLoading() {
        // hide highlights layout
        binding.linearHighlight.isVisible = false

        binding.shimmerLayoutUpNext.startShimmer()
        binding.shimmerLayoutWatchlist.startShimmer()
        binding.shimmerLayoutRecommendations.startShimmer()
        binding.shimmerLayoutNewTitles.startShimmer()
        binding.shimmerLayoutTopTen.startShimmer()
    }

    private fun setShimmerLayoutItemSize(shimmerLayout: ShimmerFrameLayout) {
        (shimmerLayout.children.first() as? LinearLayout)?.children?.forEach { child ->
            child.layoutParams.apply {
                width = (resources.displayMetrics.widthPixels / requireContext().resources.getInteger(R.integer.item_media_columns)) - itemOffset
            }
        }
    }

    private fun bindUiStateError(uiState: HomeViewModel.UiState.Error) {
        // currently not used
        Log.e(classTag, "A error occurred while loading a UiState: ${uiState.message}")
    }

    /**
     * Disable the shimmer effect for all shimmer layouts and hide them.
     */
    private fun disableShimmer() {
        binding.shimmerLayoutHighlight.apply {
            stopShimmer()
            isVisible = false
        }
        binding.shimmerLayoutUpNext.apply {
            stopShimmer()
            isVisible = false
        }
        binding.shimmerLayoutWatchlist.apply {
            stopShimmer()
            isVisible = false
        }
        binding.shimmerLayoutRecommendations.apply {
            stopShimmer()
            isVisible = false
        }
        binding.shimmerLayoutNewTitles.apply {
            stopShimmer()
            isVisible = false
        }
        binding.shimmerLayoutTopTen.apply {
            stopShimmer()
            isVisible = false
        }
    }

}
