package rest_test

import (
	"encoding/json"
	"io"
	"net/http"
	"net/http/httptest"
	"net/url"
	"strings"
	"testing"

	"github.com/labstack/echo/v5"
	"github.com/pocketbase/pocketbase/tools/rest"
)

func TestBindBody(t *testing.T) {
	scenarios := []struct {
		body        io.Reader
		contentType string
		expectBody  string
		expectError bool
	}{
		{
			strings.NewReader(""),
			echo.MIMEApplicationJSON,
			`{}`,
			false,
		},
		{
			strings.NewReader(`{"test":"invalid`),
			echo.MIMEApplicationJSON,
			`{}`,
			true,
		},
		{
			strings.NewReader(`{"test":123}`),
			echo.MIMEApplicationJSON,
			`{"test":123}`,
			false,
		},
		{
			strings.NewReader(
				url.Values{
					"string":  []string{"str"},
					"stings":  []string{"str1", "str2", ""},
					"number":  []string{"-123"},
					"numbers": []string{"123", "456.789"},
					"bool":    []string{"true"},
					"bools":   []string{"true", "false"},
				}.Encode(),
			),
			echo.MIMEApplicationForm,
			`{"bool":true,"bools":[true,false],"number":-123,"numbers":[123,456.789],"stings":["str1","str2",""],"string":"str"}`,
			false,
		},
	}

	for i, scenario := range scenarios {
		e := echo.New()
		req := httptest.NewRequest(http.MethodPost, "/", scenario.body)
		req.Header.Set(echo.HeaderContentType, scenario.contentType)
		rec := httptest.NewRecorder()
		c := e.NewContext(req, rec)

		data := map[string]any{}
		err := rest.BindBody(c, &data)

		hasErr := err != nil
		if hasErr != scenario.expectError {
			t.Errorf("[%d] Expected hasErr %v, got %v", i, scenario.expectError, hasErr)
		}

		rawBody, err := json.Marshal(data)
		if err != nil {
			t.Errorf("[%d] Failed to marshal binded body: %v", i, err)
		}

		if scenario.expectBody != string(rawBody) {
			t.Errorf("[%d] Expected body \n%s, \ngot \n%s", i, scenario.expectBody, rawBody)
		}
	}
}

func TestCopyJsonBody(t *testing.T) {
	req := httptest.NewRequest(http.MethodGet, "/", strings.NewReader(`{"test":"test123"}`))

	// simulate multiple reads from the same request
	result1 := map[string]string{}
	rest.CopyJsonBody(req, &result1)
	result2 := map[string]string{}
	rest.CopyJsonBody(req, &result2)

	if len(result1) == 0 {
		t.Error("Expected result1 to be filled")
	}

	if len(result2) == 0 {
		t.Error("Expected result2 to be filled")
	}

	if v, ok := result1["test"]; !ok || v != "test123" {
		t.Errorf("Expected result1.test to be %q, got %q", "test123", v)
	}

	if v, ok := result2["test"]; !ok || v != "test123" {
		t.Errorf("Expected result2.test to be %q, got %q", "test123", v)
	}
}
