package httputil

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

	"github.com/stretchr/testify/require"
)

func TestReadRequestBodyWithPrealloc(t *testing.T) {
	tests := []struct {
		name          string
		req           *http.Request
		wantBody      []byte
		wantErr       bool
		wantNilResult bool
	}{
		{
			name:          "nil_request",
			req:           nil,
			wantNilResult: true,
		},
		{
			name: "nil_body",
			req: &http.Request{
				Body: nil,
			},
			wantNilResult: true,
		},
		{
			name: "empty_body",
			req: &http.Request{
				Body:       http.NoBody,
				ContentLength: 0,
			},
			wantBody: []byte{},
		},
		{
			name: "small_body_content_length_100",
			req: func() *http.Request {
				body := strings.NewReader("small body content")
				return &http.Request{
					Body:          io.NopCloser(body),
					ContentLength: 100,
				}
			}(),
			wantBody: []byte("small body content"),
		},
		{
			name: "large_body",
			req: func() *http.Request {
				data := bytes.Repeat([]byte("x"), 2000)
				return &http.Request{
					Body:          io.NopCloser(bytes.NewReader(data)),
					ContentLength: 2000,
				}
			}(),
			wantBody: bytes.Repeat([]byte("x"), 2000),
		},
		{
			name: "very_large_body",
			req: func() *http.Request {
				data := bytes.Repeat([]byte("y"), 2<<20+1000) // > 2MB
				return &http.Request{
					Body:          io.NopCloser(bytes.NewReader(data)),
					ContentLength: int64(2<<20 + 1000),
				}
			}(),
			wantBody: bytes.Repeat([]byte("y"), 2<<20+1000),
		},
		{
			name: "chunked_transfer_encoding",
			req: func() *http.Request {
				return &http.Request{
					Body:          io.NopCloser(strings.NewReader("chunked data")),
					ContentLength: -1,
				}
			}(),
			wantBody: []byte("chunked data"),
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := ReadRequestBodyWithPrealloc(tt.req)
			if tt.wantErr {
				require.Error(t, err)
				return
			}
			require.NoError(t, err)
			if tt.wantNilResult {
				require.Nil(t, got)
			} else {
				require.Equal(t, tt.wantBody, got)
			}
		})
	}
}
