package dingtalkbot

import (
	"context"
	"crypto/tls"
	"io"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/internal/extension/runner"
)

// newProbeServer is a TLS loopback double bound to the package-local webhook
// call, used to classify the credential validation probe.
func newProbeServer(t *testing.T, status int, body string) *runner.RESTClient {
	t.Helper()
	server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		_, err := io.ReadAll(r.Body)
		require.NoError(t, err)
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(status)
		_, _ = w.Write([]byte(body))
	}))
	t.Cleanup(server.Close)
	client, err := runner.NewRESTClient(runner.RESTOptions{
		BaseURL: server.URL,
		Auth:    AuthSpec(),
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
		},
	})
	require.NoError(t, err)
	return client
}

func TestValidationProbeClassification(t *testing.T) {
	t.Parallel()

	cases := []struct {
		name    string
		status  int
		body    string
		wantErr bool
		code    runner.ErrorCode
	}{
		{
			name:   "invalid msgtype proves the webhook",
			status: http.StatusOK, body: `{"errcode":40035,"errmsg":"bad msgtype"}`,
		},
		{
			name:   "keyword miss proves the webhook",
			status: http.StatusOK, body: `{"errcode":310000,"errmsg":"keywords not in content:..."}`,
		},
		{
			name:   "other 310000 message rejects the credential",
			status: http.StatusOK, body: `{"errcode":310000,"errmsg":"sign not match"}`,
			wantErr: true, code: runner.ErrorProviderAuthUnavailable,
		},
		{
			name:   "token rejection",
			status: http.StatusOK, body: `{"errcode":400101,"errmsg":"invalid token"}`,
			wantErr: true, code: runner.ErrorProviderAuthUnavailable,
		},
		{
			name:   "rate limited probe surfaces",
			status: http.StatusOK, body: `{"errcode":410100,"errmsg":"too fast"}`,
			wantErr: true, code: runner.ErrorRateLimited,
		},
		{
			name:   "unknown business code fails closed",
			status: http.StatusOK, body: `{"errcode":777777,"errmsg":"mystery"}`,
			wantErr: true, code: runner.ErrorUpstreamFailure,
		},
		{
			name:   "malformed probe body fails closed",
			status: http.StatusOK, body: `oops`,
			wantErr: true, code: runner.ErrorUpstreamFailure,
		},
	}
	for _, testCase := range cases {
		t.Run(testCase.name, func(t *testing.T) {
			t.Parallel()
			_, _, err := callWebhook(context.Background(), newProbeServer(t, testCase.status, testCase.body),
				runner.Credentials{APIKeyField: "token123"},
				map[string]any{"msgtype": "__validation_probe__"})
			if !testCase.wantErr {
				require.NoError(t, err)
				return
			}
			require.Error(t, err)
			require.Equal(t, testCase.code, runner.CodeOf(err))
		})
	}
}
