package watch_aggregator //nolint:staticcheck

import (
	"bytes"
	"encoding/json"
	"errors"
	"io"
	"net/http"
	"testing"

	"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_stdlib"
	"go.uber.org/mock/gomock"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	k8swatch "k8s.io/apimachinery/pkg/watch"
)

func TestWatch_SendsWatchEvent(t *testing.T) {
	// GIVEN
	ctrl := gomock.NewController(t)

	ctx := t.Context()
	watchID := "any-watch-id"
	mockSender := NewMockwatchResponseSender(ctrl)
	mockRoundTripper := mock_stdlib.NewMockRoundTripper(ctrl)
	event := k8sWatchEvent{Type: k8swatch.Added, Object: &corev1.Pod{TypeMeta: metav1.TypeMeta{Kind: "pod", APIVersion: "v1"}}}
	b, err := json.Marshal(&event)
	require.NoError(t, err)

	mockRoundTripper.EXPECT().
		RoundTrip(gomock.Any()).
		Return(&http.Response{
			StatusCode: http.StatusOK,
			Header: http.Header{
				httpz.ContentTypeHeader: []string{acceptedContentType},
			},
			Body: io.NopCloser(bytes.NewReader(b)),
		}, nil)
	w := &watch{
		id:          watchID,
		watchParams: &WatchParams{},
		sender:      mockSender,
		rt:          mockRoundTripper,
	}

	// THEN
	gomock.InOrder(
		mockSender.EXPECT().sendEvent(watchID, gomock.Any()),
		mockSender.EXPECT().sendStop(watchID),
	)

	// WHEN
	w.handle(ctx)
}

func TestWatch_WhenUnableToCreateDownstreamWatch(t *testing.T) {
	// GIVEN
	ctrl := gomock.NewController(t)

	ctx := t.Context()
	watchID := "any-watch-id"
	mockSender := NewMockwatchResponseSender(ctrl)
	mockRoundTripper := mock_stdlib.NewMockRoundTripper(ctrl)
	event := &metav1.Status{TypeMeta: metav1.TypeMeta{Kind: "status", APIVersion: "v1"}, Status: "Failure", Message: "something went wrong"}
	b, err := json.Marshal(&event)
	require.NoError(t, err)

	mockRoundTripper.EXPECT().
		RoundTrip(gomock.Any()).
		Return(&http.Response{
			StatusCode: http.StatusBadRequest,
			Header: http.Header{
				httpz.ContentTypeHeader: []string{acceptedContentType},
			},
			Body: io.NopCloser(bytes.NewReader(b)),
		}, nil)
	w := &watch{
		id:          watchID,
		watchParams: &WatchParams{},
		sender:      mockSender,
		rt:          mockRoundTripper,
	}

	// THEN
	mockSender.EXPECT().sendError(watchID, watchRequestFailedErrorType, errors.New("unable to watch"), gomock.Any())

	// WHEN
	w.handle(ctx)
}
