package api

import (
	"net/http"

	"github.com/pingcap/schrodinger/config"
	"github.com/pingcap/schrodinger/manager/core"
	"github.com/pingcap/schrodinger/pkg/test_client"
	"github.com/pingcap/schrodinger/util"
	"github.com/unrolled/render"
)

// ManagerHandler is manager api handler
type ManagerHandler struct {
	mgr *core.Manager
	rdr *render.Render
}

func newManagerHandler(mgr *core.Manager) *ManagerHandler {
	rdr := render.New(render.Options{
		IndentJSON: true,
	})

	return &ManagerHandler{
		mgr: mgr,
		rdr: rdr,
	}
}

// ManagerConfig returns manager config for test client
func (h *ManagerHandler) ManagerConfig(w http.ResponseWriter, r *http.Request) {
	conf := &client.ManagerConfig{
		PublicNode:      config.GetGlobalConfig().Test.PublicNode,
		AgentPort:       config.GetGlobalConfig().Cat.AgentPort,
		TidbServicePort: config.GetGlobalConfig().Cat.TidbServicePort,
		TikvServicePort: config.GetGlobalConfig().Cat.TikvServicePort,
		PdServicePort:   config.GetGlobalConfig().Cat.PdServicePort,
		PdDataDir:       config.GetGlobalConfig().Cat.PdDataDir,
		TikvDataDir:     config.GetGlobalConfig().Cat.TikvDataDir,
		// Compatible with old versions
		DataDir: config.GetGlobalConfig().Cat.TikvDataDir,
	}
	h.rdr.JSON(w, http.StatusOK, util.SuccessResponse(conf))
}

// Size is config size for running experiments and bench running experiments
type Size struct {
	Size int `json:"size"`
}

// SetGeneralExperimentRunningSizeLimit sets general experiment running size limit
func (h *ManagerHandler) SetGeneralExperimentRunningSizeLimit(w http.ResponseWriter, r *http.Request) {
	size := new(Size)
	if err := readJSON(r.Body, size); err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("read json body error %v", err))
		return
	}

	err := h.mgr.SetGeneralExperimentRunningSizeLimit(size.Size)
	if err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("set general experiment running size error: %v", err))
		return
	}
	h.rdr.JSON(w, http.StatusOK, util.SuccessResponse("ok"))
}

// GetGeneralExperimentRunningSizeLimit gets general experiment running size limit
func (h *ManagerHandler) GetGeneralExperimentRunningSizeLimit(w http.ResponseWriter, r *http.Request) {
	size, err := h.mgr.GetGeneralExperimentRunningSizeLimit()
	if err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("get general experiment running size error %v", err))
		return
	}
	h.rdr.JSON(w, http.StatusOK, util.SuccessResponse(size))
}

// GetAllExperimentRunningSizeLimit gets all experiment running size limit
func (h *ManagerHandler) GetAllExperimentRunningSizeLimit(w http.ResponseWriter, r *http.Request) {
	generalSize, err := h.mgr.GetGeneralExperimentRunningSizeLimit()
	if err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("get general experiment running size error %v", err))
		return
	}

	benchSize, err := h.mgr.GetBenchExperimentRunningSizeLimit()
	if err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("get general experiment running size error %v", err))
		return
	}
	h.rdr.JSON(w, http.StatusOK, util.SuccessResponse(generalSize+benchSize))
}

// SetBenchExperimentRunningSizeLimit sets bench experiment running limit
func (h *ManagerHandler) SetBenchExperimentRunningSizeLimit(w http.ResponseWriter, r *http.Request) {
	size := new(Size)
	if err := readJSON(r.Body, size); err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("read json body error %v", err))
		return
	}

	err := h.mgr.SetBenchExperimentRunningSizeLimit(size.Size)
	if err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("set bench experiment running size error %v", err))
		return
	}
	h.rdr.JSON(w, http.StatusOK, util.SuccessResponse("ok"))
}

// GetBenchExperimentRunningSizeLimit gets bench experiment size limit
func (h *ManagerHandler) GetBenchExperimentRunningSizeLimit(w http.ResponseWriter, r *http.Request) {
	size, err := h.mgr.GetBenchExperimentRunningSizeLimit()
	if err != nil {
		h.rdr.JSON(w, http.StatusOK, util.ErrResponsef("get bench experiment running size error %v", err))
		return
	}
	h.rdr.JSON(w, http.StatusOK, util.SuccessResponse(size))
}
