package api

import (
	"io"
	"net/http"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/httpz"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/testing/mock_gitlab"
	"gitlab.com/gitlab-org/cluster-integration/gitlab-agent/v18/internal/tool/testing/testhelpers"
	"go.opentelemetry.io/otel/trace"
)

const (
	getRawCIJobsReqBody = `{"some":"request"}`
)

func TestGetRawCIJobs(t *testing.T) {
	ctx, traceID := testhelpers.CtxWithSpanContext(t)
	response := map[string]any{
		"some": "response",
	}
	c := mock_gitlab.SetupClient(t, "", JobsRequestAPIPath, func(w http.ResponseWriter, r *http.Request) {
		assertGetRawCIJobsRequest(t, r, traceID)
		w.Header()[httpz.RequestIDHeader] = []string{"1234"}
		testhelpers.RespondWithJSONAndStatus(t, w, http.StatusCreated, response)
	})
	statusCode, rawResp, respID, err := GetRawCIJobs(ctx, c, testhelpers.AgentToken, []byte(getRawCIJobsReqBody))
	require.NoError(t, err)
	defer rawResp.Free()
	assert.Equal(t, http.StatusCreated, statusCode)
	assert.JSONEq(t, `{"some": "response"}`, string(rawResp.Materialize()))
	assert.Equal(t, "1234", respID)
}

func TestGetRawCIJobs_NoResponseID(t *testing.T) {
	ctx, traceID := testhelpers.CtxWithSpanContext(t)
	response := map[string]any{
		"some": "response",
	}
	c := mock_gitlab.SetupClient(t, "", JobsRequestAPIPath, func(w http.ResponseWriter, r *http.Request) {
		assertGetRawCIJobsRequest(t, r, traceID)
		testhelpers.RespondWithJSONAndStatus(t, w, http.StatusCreated, response)
	})
	statusCode, rawResp, respID, err := GetRawCIJobs(ctx, c, testhelpers.AgentToken, []byte(getRawCIJobsReqBody))
	require.NoError(t, err)
	defer rawResp.Free()
	assert.Equal(t, http.StatusCreated, statusCode)
	assert.JSONEq(t, `{"some": "response"}`, string(rawResp.Materialize()))
	assert.Empty(t, respID)
}

func TestGetRawCIJobs_NoJobs(t *testing.T) {
	ctx, traceID := testhelpers.CtxWithSpanContext(t)
	c := mock_gitlab.SetupClient(t, "", JobsRequestAPIPath, func(w http.ResponseWriter, r *http.Request) {
		assertGetRawCIJobsRequest(t, r, traceID)
		w.Header()[httpz.RequestIDHeader] = []string{"1234"}
		w.WriteHeader(http.StatusNoContent)
	})
	statusCode, rawResp, respID, err := GetRawCIJobs(ctx, c, testhelpers.AgentToken, []byte(getRawCIJobsReqBody))
	require.NoError(t, err)
	assert.Nil(t, rawResp)
	assert.Equal(t, http.StatusNoContent, statusCode)
	assert.Equal(t, "1234", respID)
}

func assertGetRawCIJobsRequest(t *testing.T, r *http.Request, traceID trace.TraceID) {
	testhelpers.AssertRequestAcceptJSON(t, r)
	testhelpers.AssertRequestMethod(t, r, http.MethodPost)
	testhelpers.AssertRequestContentTypeJSON(t, r)
	testhelpers.AssertCommonRequestParams(t, r, traceID)
	req, err := io.ReadAll(r.Body)
	assert.NoError(t, err)
	// we want to check for EXACT equality
	assert.Equal(t, getRawCIJobsReqBody, string(req)) //nolint: testifylint
}
