package handler

import (
	"net/http"

	"github.com/labstack/echo/v4"

	"github.com/pingcap/test-infra/common/model"

	reqM "github.com/pingcap/test-infra/common/model/tcms/request"

	serror "github.com/pingcap/test-infra/services/tcms/service/common/errors"

	"github.com/pingcap/test-infra/services/tcms/utils"
)

// GetTriage ...
// @Summary get triage by plan-executions id
// @ID get-triage
// @Tags plan-execution
// @Security Bearer
// @Param id path integer true "Triage PlanExecutionID"
// @Success 200 {object} model.Triage
// @Failure default {object} HTTPError
// @Router /plan-executions/{id}/triage [get]
func (h *HTTPHandler) GetTriage(c echo.Context) error {
	ctx := c.(utils.Context)

	id, err := utils.ParseID(ctx.Param("id"))
	if err != nil {
		return serror.New(http.StatusBadRequest, err)
	}

	log := ctx.Log().With("execID", id)
	log.Infof("GetTriage")

	triage, err := h.service.Triage.GetPlanTriage(ctx, id)
	if err != nil {
		log.Errorf(err, "GetTriage failed")
		return err
	} else if triage == nil {
		return serror.NewMsg(http.StatusNotFound, "triage of plan execution %d not found", id)
	}

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

// UpdateTriage ...
// @Summary update triage by plan-executions id
// @ID update-triage
// @Tags plan-execution
// @Security Bearer
// @Param id path integer true "Triage PlanExecutionsID"
// @Param triage body reqM.PlanTriageUpdateRequest true "PlanTriage to update"
// @Success 200 {object} map[string]interface{}
// @Failure default {object} HTTPError
// @Router /plan-executions/{id}/triage [put]
func (h *HTTPHandler) UpdateTriage(c echo.Context) error {
	ctx := c.(utils.Context)

	id, err := utils.ParseID(ctx.Param("id"))
	if err != nil {
		return serror.New(http.StatusBadRequest, err)
	}

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

	log := ctx.Log().With("execID", id, "payload", req)
	log.Infof("UpdateTriage")

	err = h.service.Triage.UpdatePlanTriage(ctx, id, req)
	if err != nil {
		log.Errorf(err, "UpdateTriage failed")
		return err
	}

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

// GetCaseTriage ...
// @Summary get case triage by case-executions id
// @ID get-case-triage
// @Tags case-execution
// @Security Bearer
// @Param id path integer true "Triage CaseExecutionID"
// @Success 200 {object} model.CaseTriage
// @Failure default {object} HTTPError
// @Router /case-executions/{id}/triage [get]
func (h *HTTPHandler) GetCaseTriage(c echo.Context) error {
	ctx := c.(utils.Context)

	id, err := utils.ParseID(ctx.Param("id"))
	if err != nil {
		return serror.New(http.StatusBadRequest, err)
	}

	log := ctx.Log().With("caseExecID", id)
	log.Infof("GetCaseTriage")

	caseTriage, err := h.service.Triage.GetCaseTriage(ctx, id)
	if err != nil {
		log.Errorf(err, "GetCaseTriage failed")
		return err
	} else if caseTriage == nil {
		return serror.NewMsg(http.StatusNotFound, "triage of case execution %d not found", id)
	}

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

// CreateCaseTriage ...
// @Summary create case triage
// @Tags case-execution
// @Security Bearer
// @Param triage body model.CaseTriage true "CaseTriage to create"
// @Success 200 {object} map[string]interface{}
// @Failure default {object} HTTPError
// @Router /case-executions/triages [post]
func (h *HTTPHandler) CreateCaseTriage(c echo.Context) error {
	ctx := c.(utils.Context)

	caseTriage := &model.CaseTriage{}
	if err := ctx.Bind(caseTriage); err != nil {
		return serror.New(http.StatusBadRequest, err)
	}

	log := ctx.Log().With("planExecID", caseTriage.PlanExecutionID, "caseExecID", caseTriage.CaseExecutionID)
	log.Infof("CreateCaseTriage")

	res, err := h.service.Triage.CreateCaseTriage(ctx, caseTriage)
	if err != nil {
		log.Errorf(err, "CreateCaseTriage failed")
		return err
	}

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

// UpdateCaseTriage ...
// @Summary update case triage by case-executions id
// @ID update-case-triage
// @Tags case-execution
// @Security Bearer
// @Param id path integer true "Triage CaseExecutionsID"
// @Param triage body reqM.CaseTriageUpdateRequest true "CaseTriage to update"
// @Success 200 {object} map[string]interface{}
// @Failure default {object} HTTPError
// @Router /case-executions/{id}/triage [put]
func (h *HTTPHandler) UpdateCaseTriage(c echo.Context) error {
	ctx := c.(utils.Context)

	id, err := utils.ParseID(ctx.Param("id"))
	if err != nil {
		return serror.New(http.StatusBadRequest, err)
	}

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

	log := ctx.Log().With("execID", id, "payload", req)
	log.Infof("UpdateCaseTriage")

	err = h.service.Triage.UpdateCaseTriage(ctx, id, req)
	if err != nil {
		log.Errorf(err, "UpdateCaseTriage failed")
		return err
	}

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

// SuggestCaseTriage ...
// @Summary get case triage suggestions by case-executions id
// @ID suggest-case-triage
// @Tags case-execution
// @Param id path integer true "Triage CaseExecutionID"
// @Success 200 {object} []model.CaseTriage
// @Failure default {object} HTTPError
// @Router /case-executions/{id}/triage/suggest [get]
func (h *HTTPHandler) SuggestCaseTriage(c echo.Context) error {
	ctx := c.(utils.Context)

	id, err := utils.ParseID(ctx.Param("id"))
	if err != nil {
		return serror.New(http.StatusBadRequest, err)
	}

	log := ctx.Log().With("caseExecID", id)
	log.Infof("SuggestCaseTriage")

	caseTriages, err := h.service.Triage.SuggestCaseTriages(ctx, id)
	if err != nil {
		log.Errorf(err, "SuggestCaseTriage failed")
		return err
	}

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

// ForkCaseTriage ...
// @Summary update triage by plan-executions id
// @ID fork-case-triage
// @Tags plan-execution
// @Security Bearer
// @Param id path integer true "Triage CaseExecutionID"
// @Param from query string true "lease to set"
// @Success 200 {object} model.CaseTriage
// @Failure default {object} HTTPError
// @Router /case-executions/{id}/triage/fork [put]
func (h *HTTPHandler) ForkCaseTriage(c echo.Context) error {
	ctx := c.(utils.Context)

	id, err := utils.ParseID(ctx.Param("id"))
	if err != nil {
		return serror.New(http.StatusBadRequest, err)
	}

	forkFrom, err := utils.ParseID(ctx.QueryParam("from"))
	if err != nil {
		return serror.NewMsg(http.StatusBadRequest, "parameter 'from' should not be empty")
	}
	log := ctx.Log().With("caseID", id, "forkFrom", forkFrom)
	log.Infof("ForkTriage")

	caseTriage, err := h.service.Triage.ForkCaseTriages(ctx, id, forkFrom)
	if err != nil {
		log.Errorf(err, "ForkTriage failed")
		return err
	}

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