package internal_test

import (
	"strconv"
	"testing"

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

	"tildegit.org/tjp/gus/internal"
)

func TestPathTree(t *testing.T) {
	type pattern struct {
		string
		int
	}
	type matchresult struct {
		value  int
		params map[string]string
		failed bool
	}
	tests := []struct {
		// path-matching pattern and the integers the tree stores for each
		patterns []pattern

		// paths to match against, and the int we get and captured params
		paths map[string]matchresult
	}{
		{
			patterns: []pattern{
				{"/a", 1},
				{"/a/*rest", 2},
				{"/a/b", 3},
				{"/c", 4},
				{"/x/:y/z/*rest", 5},
			},
			paths: map[string]matchresult{
				"/a": {
					value:  1,
					params: map[string]string{},
				},
				"/a/other": {
					value:  2,
					params: map[string]string{"rest": "other"},
				},
				"/a/b": {
					value:  3,
					params: map[string]string{},
				},
				"/a/b/c": {
					value:  2,
					params: map[string]string{"rest": "b/c"},
				},
				"/c": {
					value:  4,
					params: map[string]string{},
				},
				"/c/d": {
					failed: true,
				},
				"/x/foo/z/bar/baz": {
					value:  5,
					params: map[string]string{"y": "foo", "rest": "bar/baz"},
				},
				"/": {
					failed: true,
				},
			},
		},
		{
			patterns: []pattern{
				{"/", 10},
			},
			paths: map[string]matchresult{
				"/":    {value: 10, params: map[string]string{}},
				"/foo": {failed: true},
			},
		},
	}

	for i, test := range tests {
		t.Run(strconv.Itoa(i+1), func(t *testing.T) {
			tree := &internal.PathTree[int]{}
			for _, pattern := range test.patterns {
				tree.Add(pattern.string, pattern.int)
			}

			for path, result := range test.paths {
				t.Run(path, func(t *testing.T) {
					n, params := tree.Match(path)
					if result.failed {
						require.Nil(t, n)
					} else {
						require.NotNil(t, n)
						assert.Equal(t, result.value, *n)
						assert.Equal(t, result.params, params)
					}
				})
			}
		})
	}
}