package lib

import (
	"io"
	"net/url"
	"testing"

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

type SubStruct struct {
	C string `json:"c" url:"c"`
}

type ParamsStructExample struct {
	A string      `json:"a" url:"a" required:"true"`
	B string      `json:"-" url:"-"`
	C []SubStruct `json:"sub" url:"sub"`
	D []string    `json:"d" url:"d" required:"true"`
	E []string    `json:"e,omitempty" url:"e,omitempty" required:"false"`
}

func Test_Params_ToJSON(t *testing.T) {
	p := Params{
		Params: ParamsStructExample{
			A: "The a value",
			B: "The b value",
			C: []SubStruct{{C: "the c value"}},
			D: []string{"hello"},
		},
	}

	reader, err := p.ToJSON()
	assert.NoError(t, err)

	b, err := io.ReadAll(reader)
	assert.NoError(t, err)
	assert.Equal(t, "{\"a\":\"The a value\",\"d\":[\"hello\"],\"sub\":[{\"c\":\"the c value\"}]}", string(b))
}

func Test_Params_ToJSON_Missing_Require(t *testing.T) {
	p := Params{
		Params: ParamsStructExample{
			A: "The a value",
			B: "The b value",
			C: []SubStruct{{C: "the c value"}},
		},
	}

	_, err := p.ToJSON()
	assert.Error(t, err, "")

	p = Params{
		Params: ParamsStructExample{
			B: "The b value",
			C: []SubStruct{{C: "the c value"}},
			D: []string{"hello"},
		},
	}

	_, err = p.ToJSON()
	assert.Error(t, err, "")
}

func Test_Params_ToValues(t *testing.T) {
	p := Params{
		Params: ParamsStructExample{
			A: "The a value",
			B: "The b value",
			C: []SubStruct{{C: "the c value"}},
			D: []string{"hello"},
		},
	}

	values, err := p.ToValues()
	assert.NoError(t, err)
	unescaped, _ := url.QueryUnescape(values.Encode())
	assert.Equal(t, "a=The a value&d[0]=hello&sub[0][c]=the c value", unescaped)
}

type ParamsStructWithDynamicFilter struct {
	Filter interface{} `json:"filter,omitempty" url:"filter,omitempty"`
	SortBy interface{} `json:"sort_by,omitempty" url:"sort_by,omitempty"`
}

func Test_Params_ToValues_DynamicFilterAndSort(t *testing.T) {
	p := Params{
		Params: ParamsStructWithDynamicFilter{
			Filter: map[string]interface{}{"not_site_admin": "true"},
			SortBy: map[string]interface{}{"username": "asc"},
		},
	}

	values, err := p.ToValues()
	assert.NoError(t, err)
	unescaped, _ := url.QueryUnescape(values.Encode())
	assert.Equal(t, "filter[not_site_admin]=true&sort_by[username]=asc", unescaped)
}
