package it.danieleverducci.openweddingapp.ui.gallery

import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.AnimationUtils
import android.widget.Toast
import com.google.android.material.snackbar.Snackbar
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.android.volley.AuthFailureError
import com.android.volley.VolleyError
import it.danieleverducci.openweddingapp.DeRApplication
import it.danieleverducci.openweddingapp.MainActivity
import it.danieleverducci.openweddingapp.R
import it.danieleverducci.openweddingapp.entities.GalleryItem
import it.danieleverducci.openweddingapp.entities.Like
import it.danieleverducci.openweddingapp.networking.AuthenticatedItemNet
import it.danieleverducci.openweddingapp.networking.GalleryItemNet
import it.danieleverducci.openweddingapp.networking.LikeNet
import it.danieleverducci.openweddingapp.utils.SharedPreferencesManager
import java.io.File

class GalleryFragment : Fragment(), GalleryRecyclerAdapter.GalleryItemListener,
    SwipeRefreshLayout.OnRefreshListener {

    companion object {
        val TAG = "GalleryFragment"
    }

    private val galleryStream = ArrayList<GalleryItem>()
    private lateinit var grAdapter: GalleryRecyclerAdapter
    private lateinit var swipeRefreshLayout: SwipeRefreshLayout
    private lateinit var galleryItemNet: GalleryItemNet
    private lateinit var recyclerView: RecyclerView
    private lateinit var uploadingBanner: View
    private var moreItemsAvailable = true
    private var nextPage = 0
    private val checkForNewPostsHandler = Handler(Looper.getMainLooper())

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val root = inflater.inflate(R.layout.fragment_gallery, container, false)
        val token = (activity!!.applicationContext as DeRApplication).token
        if (token == null) {
            (activity as MainActivity).logout()
        } else {
            galleryItemNet = GalleryItemNet(requireContext(), token.token)
            uploadingBanner = root.findViewById(R.id.gallery_uploading)
            recyclerView = root.findViewById<RecyclerView>(R.id.gallery_recyclerview)
            swipeRefreshLayout = root.findViewById<SwipeRefreshLayout>(R.id.gallery_swiperefresh)
            swipeRefreshLayout.setOnRefreshListener(this)

            loadItems(nextPage)

            grAdapter = GalleryRecyclerAdapter(activity!!, galleryStream)
            grAdapter.onGalleryItemListener = this

            recyclerView.apply {
                setHasFixedSize(true)
                layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
                adapter = grAdapter
            }
        }

        return root
    }

    override fun onStart() {
        super.onStart()

        (activity as MainActivity).showFab(true)

        // Start timer: checks every 2 secs for new posts
        checkForNewPosts()
    }

    override fun onStop() {
        (activity as MainActivity).showFab(false)

        // Stop timer
        checkForNewPostsHandler.removeCallbacksAndMessages(null)

        super.onStop()
    }

    override fun OnGalleryItemClickedListener(item: GalleryItem) {
        val intent = Intent(context, GalleryFullscreenViewerActivity::class.java)
        intent.putExtra(GalleryFullscreenViewerActivity.EXTRAS_IMGURL, item.url)
        startActivity(intent)
    }

    override fun OnGalleryItemLikedListener(item: GalleryItem) {
        if (context == null)
            return

        val app = activity!!.applicationContext as DeRApplication
        val ln = LikeNet(requireContext(), app.token!!.token)
        if (item.currentUserLike == null) {
            // Add like
            val like = Like(item.id, app.token!!.userId)
            ln.postItem(
                object : AuthenticatedItemNet.OnItemPostedListener<Like> {
                    override fun OnItemPosted(l: Like) {
                        item.currentUserLike = l
                        grAdapter.notifyDataSetChanged()
                    }

                    override fun OnError(error: VolleyError) {
                        Log.e(TAG, error.message ?: "")
                        Toast.makeText(context, R.string.gallery_like_error, Toast.LENGTH_SHORT)
                            .show()
                    }
                },
                like
            )
        } else {
            // Remove like
            ln.deleteItem(
                object: AuthenticatedItemNet.OnItemDeletedListener<Like> {
                    override fun OnItemDeleted() {
                        item.currentUserLike = null
                        if (item.firstUserLiked?.id == app.token!!.userId) {
                            // Disliker's name is shown near the like. We have no data to change this locally, force reload.
                            onRefresh();
                        }

                        grAdapter.notifyDataSetChanged()
                    }

                    override fun OnError(error: VolleyError) {
                        Log.e(TAG, error.message ?: "")
                        Toast.makeText(context, R.string.gallery_dislike_error, Toast.LENGTH_SHORT)
                            .show()
                    }
                },
                item.currentUserLike!!.id
            )
        }
    }

    override fun OnGalleryLastItemScrolledListener() {
        loadItems(nextPage)
    }

    public fun onPhotoTaken(gi: GalleryItem) {

        val file = File(gi.imageUrl)
        if (file.exists()) {
            val token = (activity?.applicationContext as DeRApplication).token?.token
            if (token == null) {
                Log.e(TAG, "Unable to post photo: no token!")
                return
            }
            setUploading(true)
            galleryItemNet.uploadItem(
                token,
                file,
                object : GalleryItemNet.OnGalleryItemUploadCompletedListener {
                    override fun OnGalleryItemUploaded(uploadedGi: GalleryItem?, error: String) {
                        setUploading(false)
                        if (!error.isEmpty()) {
                            Snackbar.make(view!!, "${getString(R.string.upload_galleryitem_error)}: ${error}", Snackbar.LENGTH_SHORT).show()
                            return
                        }
                        if (uploadedGi != null) {
                            galleryStream.add(0, uploadedGi)
                            grAdapter.notifyDataSetChanged()
                            recyclerView.smoothScrollToPosition(0)
                        } else {
                            Snackbar.make(view!!, getString(R.string.upload_galleryitem_error), Snackbar.LENGTH_SHORT).show()
                        }
                    }
                })
        } else {
            Log.e(TAG, "Unable to find file ${file.path} for upload")
        }
    }

    override fun onRefresh() {
        moreItemsAvailable = true
        nextPage = 0
        loadItems(nextPage)
    }

    private fun loadItems(page: Int) {
        if (!moreItemsAvailable) {
            return
        }

        galleryItemNet.getList(page, object: AuthenticatedItemNet.OnItemListObtainedListener<GalleryItem> {

            override fun OnItemListObtained(
                items: ArrayList<GalleryItem>?,
                page: Int,
                more: Boolean
            ) {
                if (items == null) {
                    Log.e(TAG, "Gallery request successful but no items received!")
                    return
                }

                if (page == 0) {
                    galleryStream.clear()
                    swipeRefreshLayout.isRefreshing = false

                    // Save for cache
                    if (context != null)
                        SharedPreferencesManager.saveGalleryCache(requireContext(), items)
                }
                galleryStream.addAll(items)
                grAdapter.notifyDataSetChanged()

                moreItemsAvailable = more
                grAdapter.moreItemsAvailable = moreItemsAvailable
                if (moreItemsAvailable) {
                    nextPage++
                }
            }

            override fun OnError(error: VolleyError) {
                if (error is AuthFailureError) {
                    (activity as MainActivity).logout();
                } else {
                    Log.e(TAG, "Unable to download gallery list: ${error.toString()}")
                    if (view != null) {
                        Snackbar.make(
                            view!!,
                            R.string.gallery_network_error,
                            Snackbar.LENGTH_SHORT
                        ).show()
                    }

                    if (page == 0 && context != null) {
                        // Show cached content
                        val cachedGi = SharedPreferencesManager.loadGalleryCache(requireContext())
                        if (cachedGi != null) {
                            galleryStream.clear()
                            swipeRefreshLayout.isRefreshing = false
                            galleryStream.addAll(cachedGi)
                            grAdapter.notifyDataSetChanged()
                            moreItemsAvailable = false
                            grAdapter.moreItemsAvailable = moreItemsAvailable
                        }
                    }
                }
            }

        })
    }

    fun setUploading(uploading: Boolean) {
        uploadingBanner.visibility = if (uploading) View.VISIBLE else View.GONE
    }

    /**
     * Checks for new posts every 2 seconds.
     * Started on onStart and canceled on onStop
     */
    private fun checkForNewPosts() {
        // If list is scrolled all the way up, load new items
        if ((this.recyclerView.layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition() == 0)
            onRefresh()

        checkForNewPostsHandler.postDelayed({
            checkForNewPosts()
        }, 5000)
    }
}