package it.danieleverducci.openweddingapp.ui

import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.text.HtmlCompat
import androidx.fragment.app.Fragment
import com.android.volley.VolleyError
import com.squareup.picasso.Picasso
import it.danieleverducci.openweddingapp.Config
import it.danieleverducci.openweddingapp.R
import it.danieleverducci.openweddingapp.databinding.FragmentGenericDynamicContentBinding
import it.danieleverducci.openweddingapp.entities.LocalizedGenericDynamicContent
import it.danieleverducci.openweddingapp.entities.GenericDynamicContent
import it.danieleverducci.openweddingapp.networking.GenericDynamicContentNet
import it.danieleverducci.openweddingapp.networking.StaticItemNet
import it.danieleverducci.openweddingapp.utils.SharedPreferencesManager
import java.lang.RuntimeException
import java.util.*

abstract class GenericLocalizedContentFragment : Fragment() {
    private lateinit var binding: FragmentGenericDynamicContentBinding

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

    /**
     * Display generic content
     */
    open fun fillPageWith(loc: GenericDynamicContent) {
        val wg: LocalizedGenericDynamicContent
        if (loc.localized.containsKey(Locale.getDefault().language))
            wg = loc.localized.get(Locale.getDefault().language)!!
        else if (loc.localized.containsKey(Config.STATIC_CONTENT_DEFAULT_LOCALE))
            wg = loc.localized.get(Config.STATIC_CONTENT_DEFAULT_LOCALE)!!
        else
            throw RuntimeException("Unsupported locale")

        // Image
        Picasso.get()
            .load(wg.pictureUrl)
            .into(binding.image)

        // Text
        binding.name.text = wg.name
        binding.content.text = HtmlCompat.fromHtml(wg.content, HtmlCompat.FROM_HTML_MODE_LEGACY)
    }

    /**
     * Loads generic content from shared preferences, if any.
     * Then, tries to update the generic content from static online service.
     * To be implemented by extender class
     */
    fun loadContent() {
        // Load from cache
        val gdc = SharedPreferencesManager.loadGenericDynamicContent(requireContext(), getSharedPreferencesKey(), getDefaultRawRes())
        fillPageWith(gdc)

        // Load/update from net
        GenericDynamicContentNet(requireContext()).getItem(getEndpoint(), object: StaticItemNet.OnItemObtainedListener<GenericDynamicContent> {
            override fun OnItemObtained(item: GenericDynamicContent) {
                if(item.version > gdc.version) {
                    fillPageWith(item)
                    SharedPreferencesManager.saveGenericDynamicContent(requireContext(), item, getSharedPreferencesKey())
                    Log.d(getLogTag(), "Updated ${getName()}: local ${gdc.version}, remote ${item.version}")
                } else {
                    Log.d(getLogTag(), "${getName()} up to date: local ${gdc.version}, remote ${item.version}")
                }
            }

            override fun OnError(error: VolleyError) {
                Log.d(getLogTag(), "Unable to update ${getName()}: ${error}")
            }
        })
    }

    /**
     * Appends a view at bottom.
     */
    fun appendView(v: View) {
        binding.container.addView(v)
    }

    /**
     * Returns the shared preferences key used to cache the element
     */
    fun getSharedPreferencesKey(): String {
        return getName()
    }

    /**
     * Returns the shared preferences key used to cache the element
     */
    fun getLogTag(): String {
        return "${getName()}Fragment"
    }

    /**
     * Returns the object name. Used to determine the cache key, the log tag etc...
     */
    abstract fun getName(): String

    /**
     * Returns the json endpoint (relative)
     */
    abstract fun getEndpoint(): String

    /**
     * Returns the raw resource containing the default json
     */
    abstract fun getDefaultRawRes(): Int

}