package im

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

	lark "github.com/larksuite/oapi-sdk-go/v3"
	"github.com/stretchr/testify/require"
)

type testHTTPClientFunc func(req *http.Request) (*http.Response, error)

func (f testHTTPClientFunc) Do(req *http.Request) (*http.Response, error) {
	return f(req)
}

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

	requestCount := 0
	rawClient := lark.NewClient("app-id", "app-secret", lark.WithHttpClient(testHTTPClientFunc(
		func(req *http.Request) (*http.Response, error) {
			switch req.URL.Path {
			case "/open-apis/auth/v3/tenant_access_token/internal":
				return testJSONResponse(`{"code":0,"expire":7200,"tenant_access_token":"token"}`), nil
			case "/open-apis/im/v1/messages":
				requestCount++
				require.Equal(t, "chat", req.URL.Query().Get("container_id_type"))
				require.Equal(t, "oc_chat", req.URL.Query().Get("container_id"))
				require.Equal(t, "50", req.URL.Query().Get("page_size"))
				require.Equal(t, "ByCreateTimeAsc", req.URL.Query().Get("sort_type"))
				if requestCount == 1 {
					require.Empty(t, req.URL.Query().Get("page_token"))
					return testJSONResponse(`{"code":0,"data":{"has_more":true,"page_token":"next","items":[{"message_id":"om_1"}]}}`), nil
				}
				require.Equal(t, "next", req.URL.Query().Get("page_token"))
				return testJSONResponse(`{"code":0,"data":{"has_more":false,"items":[{"message_id":"om_2"}]}}`), nil
			default:
				t.Fatalf("unexpected request path: %s", req.URL.Path)
				return nil, nil
			}
		},
	)))

	data, err := New(rawClient).ListMessages(context.Background(), "oc_chat", "1", "2")
	require.NoError(t, err)
	require.Len(t, data.Items, 2)
	require.Equal(t, "om_1", *data.Items[0].MessageId)
	require.Equal(t, "om_2", *data.Items[1].MessageId)
	require.Equal(t, 2, requestCount)
}

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

	requestCount := 0
	rawClient := lark.NewClient("app-id", "app-secret", lark.WithHttpClient(testHTTPClientFunc(
		func(req *http.Request) (*http.Response, error) {
			switch req.URL.Path {
			case "/open-apis/auth/v3/tenant_access_token/internal":
				return testJSONResponse(`{"code":0,"expire":7200,"tenant_access_token":"token"}`), nil
			case "/open-apis/im/v1/messages":
				requestCount++
				return testJSONResponse(`{"code":0,"data":{"has_more":true,"page_token":"repeated","items":[]}}`), nil
			default:
				t.Fatalf("unexpected request path: %s", req.URL.Path)
				return nil, nil
			}
		},
	)))

	data, err := New(rawClient).ListMessages(context.Background(), "oc_chat", "1", "2")
	require.Nil(t, data)
	require.EqualError(t, err, "list messages failed: repeated page token")
	require.Equal(t, 2, requestCount)
}

func testJSONResponse(body string) *http.Response {
	header := make(http.Header)
	header.Set("Content-Type", "application/json")
	return &http.Response{
		StatusCode: http.StatusOK,
		Header:     header,
		Body:       io.NopCloser(strings.NewReader(body)),
	}
}
