package api

import (
	"net/http"
	"strconv"

	"github.com/gorilla/mux"
	"github.com/pingcap/schrodinger/pkg/types"
	"github.com/pingcap/schrodinger/util"
)

// CreateObject creates object
func (h *ManagerHandler) CreateObject(w http.ResponseWriter, r *http.Request) {
	object := new(types.Object)
	if err := readJSON(r.Body, object); err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("read json body %v", err))
		return
	}

	if err := h.mgr.CreateObject(object); err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("set object %+v error %v", object, err))
		return
	}
	h.rdr.JSON(w, http.StatusOK, util.SuccessResponse(object))
}

// UpdateObject updates object
func (h *ManagerHandler) UpdateObject(w http.ResponseWriter, r *http.Request) {
	id, err := strconv.ParseInt(mux.Vars(r)["id"], 10, 64)
	if err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("parse object id error %v", err))
		return
	}
	object := new(types.Object)
	if err := readJSON(r.Body, object); err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("read json body %v", err))
		return
	}

	object.ID = id
	if err := h.mgr.UpdateObject(object); err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("set object %+v error %v", object, err))
		return
	}
	h.rdr.JSON(w, http.StatusOK, util.SuccessResponse(object))
}

// ListObjects lists objects
func (h *ManagerHandler) ListObjects(w http.ResponseWriter, r *http.Request) {
	objs := h.mgr.ListObject()

	size := getSize(r)
	offset := getOffset(r)
	start, end := getPagingIndexes(int64(len(objs)), offset, size)

	listData := ListData{
		List:   objs[start:end],
		Offset: offset,
		Size:   size,
		Total:  int64(len(objs)),
	}
	h.rdr.JSON(w, http.StatusOK, util.SuccessResponse(listData))
}

// ListObjectsByExperimentID lists object by experiment
func (h *ManagerHandler) ListObjectsByExperimentID(w http.ResponseWriter, r *http.Request) {
	id, err := strconv.ParseInt(mux.Vars(r)["experimentID"], 10, 64)
	if err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("parse experiment id error %v", err))
		return
	}
	objs := h.mgr.ListObjectByExperimentID(id)

	size := getSize(r)
	offset := getOffset(r)
	start, end := getPagingIndexes(int64(len(objs)), offset, size)

	listData := ListData{
		List:   objs[start:end],
		Offset: offset,
		Size:   size,
		Total:  int64(len(objs)),
	}
	h.rdr.JSON(w, http.StatusOK, util.SuccessResponse(listData))
}

// GetObjectByExperimentID gets object by experiment
func (h *ManagerHandler) GetObjectByExperimentID(w http.ResponseWriter, r *http.Request) {
	id, err := strconv.ParseInt(mux.Vars(r)["experimentID"], 10, 64)
	if err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("parse experiment id error %v", err))
		return
	}

	name := mux.Vars(r)["name"]
	if util.IsEmpty(name) {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("object name is empty"))
		return
	}

	objs := h.mgr.ListObjectByExperimentID(id)
	if len(objs) < 1 {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("not found object"))
		return
	}

	for _, obj := range objs {
		if obj.Name == name {
			h.rdr.JSON(w, http.StatusOK, util.SuccessResponse(obj))
			return
		}
	}

	h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("not found object"))
}

// GetObjectByBoxID gets object by experiment
func (h *ManagerHandler) GetObjectByBoxID(w http.ResponseWriter, r *http.Request) {
	id, err := strconv.ParseInt(mux.Vars(r)["boxID"], 10, 64)
	if err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("parse experiment id error %v", err))
		return
	}

	name := mux.Vars(r)["name"]
	if util.IsEmpty(name) {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("object name is empty"))
		return
	}

	objs := h.mgr.ListObjectByBoxID(id)
	if len(objs) < 1 {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("not found object"))
		return
	}

	for _, obj := range objs {
		if obj.Name == name {
			h.rdr.JSON(w, http.StatusOK, util.SuccessResponse(obj))
			return
		}
	}

	h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("not found object"))
}

// ListObjectsByBoxID lists object by experiment
func (h *ManagerHandler) ListObjectsByBoxID(w http.ResponseWriter, r *http.Request) {
	id, err := strconv.ParseInt(mux.Vars(r)["boxID"], 10, 64)
	if err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("parse box id error %v", err))
		return
	}
	objs := h.mgr.ListObjectByBoxID(id)

	size := getSize(r)
	offset := getOffset(r)
	start, end := getPagingIndexes(int64(len(objs)), offset, size)

	listData := ListData{
		List:   objs[start:end],
		Offset: offset,
		Size:   size,
		Total:  int64(len(objs)),
	}
	h.rdr.JSON(w, http.StatusOK, util.SuccessResponse(listData))
}

// GetObject gets object
func (h *ManagerHandler) GetObject(w http.ResponseWriter, r *http.Request) {
	id, err := strconv.ParseInt(mux.Vars(r)["id"], 10, 64)
	if err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("parse object id error %v", err))
		return
	}

	obj, err := h.mgr.GetObject(id)
	if err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("get object %d error %v", id, err))
		return
	}

	h.rdr.JSON(w, http.StatusOK, util.SuccessResponse(obj))
}
