package server

import (
	"regexp"
	"strings"
	"testing"
)

func TestParseUrl(t *testing.T) {
	tests := []struct {
		name   string
		input  string
		output UrlParamMatcher
	}{
		{
			name:  "Empty Path",
			input: "http://example.com",
			output: UrlParamMatcher{
				Params: []string{},
				Reg:    nil,
			},
		},
		{
			name:  "Path with No Parameters",
			input: "http://example.com/path/to/file",
			output: UrlParamMatcher{
				Params: []string{},
				Reg:    nil,
			},
		},
		{
			name:  "Path with Parameters",
			input: "http://example.com/:param1/:param2/:file",
			output: UrlParamMatcher{
				Params: []string{"param1", "param2", "file"},
				Reg:    regexp.MustCompile("^/(?P<param1>.*)/(?P<param2>.*)/(?P<file>.*)$"),
			},
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			result := ParseUrl(test.input)
			if !UrlMatcherEqual(result, test.output) {
				t.Errorf("Expected %v, but got %v", test.output, result)
			}
		})
	}
}

func UrlMatcherEqual(a, b UrlParamMatcher) bool {

	if strings.Join(a.Params, ";") != strings.Join(b.Params, ";") {
		return false
	}

	if a.Reg == nil || b.Reg == nil {
		return a.Reg == nil && b.Reg == nil
	}
	if a.Reg.String() != b.Reg.String() {
		return false
	}
	return true
}

func TestMatchUrlParam(t *testing.T) {
	matcher := &UrlParamMatcher{
		Reg:    nil,
		Params: []string{"param1", "param2"},
	}

	u1 := "http://example.com/path"
	expected1 := map[string]string(nil)
	result1, found1 := MatchUrlParam(u1, matcher)
	if len(result1) != len(expected1) || !allMatch(result1, expected1) {
		t.Errorf("Test case 1 failed. Expected %v, but got %v", expected1, result1)
	}
	if found1 {
		t.Errorf("Test case 1 failed. Expected not to find a match.")
	}

	u4 := "http://example.com/param1/param2"
	matcher4 := &UrlParamMatcher{
		Reg:    regexp.MustCompile("^/(?P<param1>.*)/(?P<param2>.*)$"),
		Params: []string{"param1", "param2"},
	}
	expected4 := map[string]string{"param1": "param1", "param2": "param2"}
	result4, found4 := MatchUrlParam(u4, matcher4)
	if len(result4) != len(expected4) || !allMatch(result4, expected4) {
		t.Errorf("Test case 4 failed. Expected %v, but got %v", expected4, result4)
	}
	if !found4 {
		t.Errorf("Test case 4 failed. Expected not to find a match.")
	}
}

func allMatch(m1, m2 map[string]string) bool {
	if len(m1) != len(m2) {
		return false
	}
	for k, v1 := range m1 {
		v2, ok := m2[k]
		if !ok || v1 != v2 {
			return false
		}
	}
	return true
}
