package handler

import (
	"net/http"
	"testing"

	"github.com/stretchr/testify/assert"

	"github.com/pingcap/test-infra/common/model"
	reqM "github.com/pingcap/test-infra/common/model/tcms/request"
	respM "github.com/pingcap/test-infra/common/model/tcms/response"
	htest "github.com/pingcap/test-infra/services/tcms/tests/httptest"
)

var newCaseExecution = reqM.CaseExecutionCreateRequest{
	Meta:           map[string]string{"k1": "v1"},
	CaseID:         1,
	RootPlanExecID: 1,
	StepName:       "step-11",
	StepSeq:        11,
	Status:         "RUNNING",
	Output:         "create",
	ArgoURL:        "https://argo.url",
}

var updateCaseExecution = reqM.CaseExecutionUpdateRequest{
	Meta:        map[string]string{"k1": "v1", "k2": "v2"},
	StartedAt:   &[]model.Timestamp{1621997433}[0],
	CompletedAt: &[]model.Timestamp{1621999209}[0],
	Status:      model.ExecutionStatusCancelled,
	Output:      "update",
}

func TestListCaseExecutions(t *testing.T) {
	h := setup(t)
	defer h.Shutdown()

	_, execs := htest.MustGET[respM.CaseExecutionListResponse](h.Echo, "/api/v1/case-executions")
	assert.NotZero(t, execs.Total)

	// by ids
	_, execs = htest.MustGET[respM.CaseExecutionListResponse](h.Echo, "/api/v1/case-executions?ids=1,2&offset=0&count=2")
	assert.Equal(t, 2, execs.Total)
	assert.NotEmpty(t, execs.Data[0].CaseIDAndName.Name)

	// by root_plan_exec_id
	_, execs = htest.MustGET[respM.CaseExecutionListResponse](h.Echo, "/api/v1/case-executions?root_plan_exec_id=2&status=SUCCESS&offset=0&count=2")
	assert.Equal(t, 2, execs.Total)
	assert.Equal(t, model.ID(2), execs.Data[0].RootPlanID)
}

func TestGetCaseExecution(t *testing.T) {
	h := setup(t)
	defer h.Shutdown()

	_, exec := htest.MustGET[model.TestCaseExecution](h.Echo, "/api/v1/case-executions/2")
	assert.Equal(t, 2, int(exec.ID))
	assert.NotNil(t, exec.StartedAt)
	assert.Equal(t, 2, len(exec.Meta))
	assert.Equal(t, 1, int(exec.CaseIDAndName.ID))
	assert.Equal(t, "case1", exec.CaseIDAndName.Name)
}

func TestCreateCaseExecution(t *testing.T) {
	h := setup(t)
	defer h.Shutdown()

	c := newCaseExecution
	_, exec := htest.MustPOST[model.TestCaseExecution](h.Echo, "/api/v1/case-executions", htest.WithJSON(c))
	assert.Equal(t, c.RootPlanExecID, exec.RootPlanExecID)
	assert.Equal(t, c.StepName, exec.StepName)
	assert.Equal(t, c.StepSeq, exec.StepSeq)
	assert.Equal(t, len(c.Meta), len(exec.Meta))
	assert.Equal(t, c.ArgoURL, exec.ArgoURL)
}

func TestUpdateCaseExecution(t *testing.T) {
	h := setup(t)
	defer h.Shutdown()

	// update case 1
	_, exec := htest.MustPUT[model.TestCaseExecution](h.Echo, "/api/v1/case-executions/1", htest.WithJSON(updateCaseExecution))
	assert.Equal(t, updateCaseExecution.Status, exec.Status)
	assert.Equal(t, len(updateCaseExecution.Meta), len(exec.Meta))
	assert.Equal(t, updateCaseExecution.ArgoURL, exec.ArgoURL)
}

func TestUpdateCaseExecutionNote(t *testing.T) {
	h := setup(t)
	defer h.Shutdown()

	note := "123"

	// update case-exec 1
	_, _ = htest.MustPUT[model.TestCaseExecution](h.Echo, "/api/v1/case-executions/1/note", htest.WithJSON(reqM.ExecutionNoteUpdateRequest{Note: note}))

	// get case-exec 1
	_, exec := htest.MustGET[model.TestCaseExecution](h.Echo, "/api/v1/case-executions/1")
	assert.Equal(t, note, exec.Note)
}

func TestUpdateCaseExecutionReason(t *testing.T) {
	h := setup(t)
	defer h.Shutdown()

	reason := model.ExecFailReasonProduct

	// update case-exec 1
	rec, _ := htest.MustPUT[model.TestCaseExecution](h.Echo, "/api/v1/case-executions/1/reason", htest.WithJSON(reqM.ExecutionReasonUpdateRequest{Reason: reason}))
	assert.Equal(t, http.StatusOK, rec.Code)

	// get case-exec 1
	rec, exec := htest.MustGET[model.TestCaseExecution](h.Echo, "/api/v1/case-executions/1")
	assert.Equal(t, reason, exec.Reason)
}
