package handler

import (
	"net/http"

	"github.com/labstack/echo/v4"

	reqM "github.com/pingcap/test-infra/common/model/tcms/request"
	respM "github.com/pingcap/test-infra/common/model/tcms/response"
	serror "github.com/pingcap/test-infra/services/tcms/service/common/errors"
	"github.com/pingcap/test-infra/services/tcms/utils"
)

// @Summary List Resource Cohorts
// @ID list-resource-cohorts
// @Tags resource-cohort
// @Security Bearer
// @Param resourcepool query string false "Filter by resourcepool, will also return borrowedPolicy if specified"
// @Success 200 {object} respM.ResourceCohortListResponse
// @Failure default {object} HTTPError
// @Router /resource-cohorts [get]
func (h *HTTPHandler) ListResourceCohorts(c echo.Context) error {
	ctx := c.(utils.Context)

	resourcepool := c.QueryParam("resourcepool")

	log := ctx.Log()
	log.With("resourcepool", resourcepool).Infof("ListResourceCohorts")

	cohorts, err := h.service.ResourceCohort.List(ctx, resourcepool)
	if err != nil {
		log.Errorf(err, "ListResourceCohorts failed")
		return err
	}

	return ctx.JSON(http.StatusOK, respM.ResourceCohortListResponse{
		Total: len(cohorts),
		Data:  cohorts,
	})
}

// @Summary Get Resource Cohort by name.
// @ID get-resource-cohort
// @Tags resource-cohort
// @Security Bearer
// @Param name path string true "Cohort name"
// @Success 200 {object} model.ResourceCohort
// @Failure default {object} HTTPError
// @Router /resource-cohorts/{name} [get]
func (h *HTTPHandler) GetResourceCohort(c echo.Context) error {
	ctx := c.(utils.Context)

	name := c.Param("name")
	if name == "" {
		return serror.NewMsg(http.StatusBadRequest, "cohort name is required")
	}

	log := ctx.Log()
	log.With("name", name).Infof("GetResourceCohort")

	cohort, err := h.service.ResourceCohort.Get(ctx, name)
	if err != nil {
		log.Errorf(err, "GetResourceCohort failed")
		return err
	}
	if cohort == nil {
		return serror.NewMsg(http.StatusNotFound, "cohort not found")
	}

	return ctx.JSON(http.StatusOK, cohort)
}

// @Summary Create Resource Cohort.
// @ID create-resource-cohort
// @Tags resource-cohort
// @Security Bearer
// @Param cohort body reqM.ResourceCohortCreateRequest true "Cohort to create"
// @Success 200 {object} map[string]interface{}
// @Failure default {object} HTTPError
// @Router /resource-cohorts [post]
func (h *HTTPHandler) CreateResourceCohort(c echo.Context) error {
	ctx := c.(utils.Context)

	cohort := &reqM.ResourceCohortCreateRequest{}
	if err := ctx.Bind(cohort); err != nil {
		return serror.New(http.StatusBadRequest, err)
	}
	if err := cohort.Validate(); err != nil {
		return serror.New(http.StatusBadRequest, err)
	}

	log := ctx.Log()
	log.With("name", cohort.Name).Infof("CreateResourceCohort")

	err := h.service.ResourceCohort.Create(ctx, cohort)
	if err != nil {
		log.Errorf(err, "CreateResourceCohort failed")
		return err
	}

	return ctx.JSON(http.StatusOK, echo.Map{"result": "ok"})
}

// @Summary Delete Resource Cohort by name.
// @ID delete-resource-cohort
// @Tags resource-cohort
// @Security Bearer
// @Param name path string true "Cohort name"
// @Success 200 {object} map[string]interface{}
// @Failure default {object} HTTPError
// @Router /resource-cohorts/{name} [delete]
func (h *HTTPHandler) DeleteResourceCohort(c echo.Context) error {
	ctx := c.(utils.Context)

	name := ctx.Param("name")
	if name == "" {
		return serror.NewMsg(http.StatusBadRequest, "cohort name is required")
	}

	log := ctx.Log()
	log.With("name", name).Infof("DeleteResourceCohort")

	err := h.service.ResourceCohort.Delete(ctx, name)
	if err != nil {
		log.Errorf(err, "DeleteResourceCohort failed")
		return err
	}

	return ctx.JSON(http.StatusOK, echo.Map{"result": "ok"})
}

// @Summary Add Resource Pool to Resource Cohort.
// @ID add-pool-to-resource-cohort
// @Tags resource-cohort
// @Security Bearer
// @Param name path string true "Cohort name"
// @Param resourcepool body reqM.ResourceCohortAddPoolRequest true "resourcepool"
// @Success 200 {object} map[string]interface{}
// @Failure default {object} HTTPError
// @Router /resource-cohorts/{name}/resourcepools [post]
func (h *HTTPHandler) AddPool2ResourceCohort(c echo.Context) error {
	ctx := c.(utils.Context)

	name := ctx.Param("name")
	if name == "" {
		return serror.NewMsg(http.StatusBadRequest, "cohort name is required")
	}

	respool := &reqM.ResourceCohortAddPoolRequest{}
	if err := ctx.Bind(respool); err != nil {
		return serror.New(http.StatusBadRequest, err)
	}
	if respool.Name == "" {
		return serror.NewMsg(http.StatusBadRequest, "resourcepool name is required")
	}

	log := ctx.Log()
	log.With("name", name, "respool", respool.Name).Infof("AddPool2ResourceCohort")

	err := h.service.ResourceCohort.AddResourcePool(ctx, name, respool.Name)
	if err != nil {
		log.Errorf(err, "AddPool2ResourceCohort failed")
		return err
	}

	return ctx.JSON(http.StatusOK, echo.Map{"result": "ok"})
}

// @Summary Remove Resource Pool from Resource Cohort.
// @ID remove-pool-from-resource-cohort
// @Tags resource-cohort
// @Security Bearer
// @Param name path string true "Cohort name"
// @Param respoolName path string true "Resourcepool name"
// @Success 200 {object} map[string]interface{}
// @Failure default {object} HTTPError
// @Router /resource-cohorts/{name}/resourcepools/{respoolName} [delete]
func (h *HTTPHandler) RemovePoolFromResourceCohort(c echo.Context) error {
	ctx := c.(utils.Context)

	name := ctx.Param("name")
	if name == "" {
		return serror.NewMsg(http.StatusBadRequest, "cohort name is required")
	}

	respoolName := ctx.Param("respoolName")
	if respoolName == "" {
		return serror.NewMsg(http.StatusBadRequest, "resourcepool name is required")
	}

	log := ctx.Log()
	log.With("name", name, "respool", respoolName).Infof("RemovePoolFromResourceCohort")

	err := h.service.ResourceCohort.RemoveResourcePool(ctx, name, respoolName)
	if err != nil {
		log.Errorf(err, "RemovePoolFromResourceCohort failed")
		return err
	}

	return ctx.JSON(http.StatusOK, echo.Map{"result": "ok"})
}
