package it.danieleverducci.openweddingapp.networking

import android.content.Context
import android.util.Log
import com.android.volley.Request
import com.android.volley.RequestQueue
import com.android.volley.Response
import com.android.volley.VolleyError
import com.android.volley.toolbox.Volley
import it.danieleverducci.openweddingapp.entities.Jsonable
import org.json.JSONObject

open abstract class AuthenticatedItemNet<T: Jsonable> (val context: Context, val token: String) {
    companion object {
        val TAG = "AuthenticatedItemNet"
    }

    val queue: RequestQueue

    init {
        queue = Volley.newRequestQueue(context)
    }

    abstract fun newItem(jo: JSONObject): T

    open fun getList(baseUrl: String, page: Int, listener: OnItemListObtainedListener<T>) {
        val url = "${baseUrl}/read.php?page=${page}"
        val request = AuthenticatedJsonObjectRequest(
            token,
            Request.Method.GET,
            url,
            null,
            Response.Listener<JSONObject> {
                val records = it.getJSONArray("records")
                val page = it.getInt("page")
                val more = it.getBoolean("more")
                val items = ArrayList<T>(records.length())
                for (i in 0 until records.length()) {
                    items.add(newItem(records.getJSONObject(i)))
                }
                listener.OnItemListObtained(items, page, more)
            },
            Response.ErrorListener {
                listener.OnError(it)
            })
        queue.add(request)
    }

    open fun getItem(baseUrl: String, id: Int, listener: OnItemObtainedListener<T>) {
        val url = "${baseUrl}/get.php?id=${id}"
        val request = AuthenticatedJsonObjectRequest(
            token,
            Request.Method.GET,
            url,
            null,
            Response.Listener<JSONObject> {
                val item = newItem(it)
                listener.OnItemObtained(item)
            },
            Response.ErrorListener {
                listener.OnError(it)
            })
        queue.add(request)
    }

    open fun postItem(baseUrl: String, listener: OnItemPostedListener<T>, item: T) {
        val request = AuthenticatedJsonObjectRequest(
            token,
            Request.Method.POST,
            "${baseUrl}/create.php",
            item.toJson(),
            Response.Listener<JSONObject> {
                listener.OnItemPosted(newItem(it))
            },
            Response.ErrorListener {
                Log.e(TAG, "Unable to post item: ${it}")
                listener.OnError(it)
            }
        )
        queue.add(request)
    }

    open fun deleteItem(baseUrl: String, listener: OnItemDeletedListener<T>, id: Int) {
        val request = AuthenticatedJsonObjectRequest(
            token,
            Request.Method.DELETE,
            "${baseUrl}/delete.php?id=${id}",
            null,
            Response.Listener<JSONObject> {
                listener.OnItemDeleted()
            },
            Response.ErrorListener {
                Log.e(TAG, "Unable to delete item: ${it}")
                listener.OnError(it)
            }
        )
        queue.add(request)
    }

    interface OnItemListObtainedListener<T> {
        fun OnItemListObtained(items: ArrayList<T>?, page: Int, more: Boolean)
        fun OnError(error: VolleyError)
    }

    interface OnItemObtainedListener<T> {
        fun OnItemObtained(item: T)
        fun OnError(error: VolleyError)
    }

    interface OnItemPostedListener<T> {
        fun OnItemPosted(item: T)
        fun OnError(error: VolleyError)
    }

    interface OnItemDeletedListener<T> {
        fun OnItemDeleted()
        fun OnError(error: VolleyError)
    }

}