package matcher

import (
	"testing"

	"github.com/valyala/fasthttp"
)

func TestRadixTree_Insert_EmptyNode(t *testing.T) {
	// Case 1: 空节点
	tree := NewRadixTree()
	handler := func(ctx *fasthttp.RequestCtx) {}

	err := tree.Insert("/api", handler, 1, "prefix", false)
	if err != nil {
		t.Fatalf("insert failed: %v", err)
	}

	result := tree.FindLongestPrefix([]byte("/api"))
	if result == nil {
		t.Error("should find inserted path")
	}
	if result.Path != "/api" {
		t.Errorf("expected path /api, got %s", result.Path)
	}
}

func TestRadixTree_Insert_CommonPrefix(t *testing.T) {
	// Case 2: 公共前缀计算
	tree := NewRadixTree()
	handler1 := func(ctx *fasthttp.RequestCtx) { ctx.SetBodyString("1") }
	handler2 := func(ctx *fasthttp.RequestCtx) { ctx.SetBodyString("2") }

	tree.Insert("/api", handler1, 1, "prefix", false)
	tree.Insert("/api/users", handler2, 2, "prefix", false)

	result := tree.FindLongestPrefix([]byte("/api/users"))
	if result == nil {
		t.Fatal("expected match")
	}
	// Lower priority number wins, so /api (priority 1) beats /api/users (priority 2)
	if result.Path != "/api" {
		t.Errorf("expected path /api (priority 1), got %s", result.Path)
	}
	if result.Priority != 1 {
		t.Errorf("expected priority 1, got %d", result.Priority)
	}
}

func TestRadixTree_Insert_NodeSplit(t *testing.T) {
	// Case 4: 节点分割
	tree := NewRadixTree()
	handler1 := func(ctx *fasthttp.RequestCtx) {}
	handler2 := func(ctx *fasthttp.RequestCtx) {}

	tree.Insert("/abc", handler1, 1, "prefix", false)
	tree.Insert("/abx", handler2, 2, "prefix", false)

	// 应该正确分割 /ab 公共前缀
	result := tree.FindLongestPrefix([]byte("/abc"))
	if result == nil {
		t.Error("should find /abc after split")
	}
}

func TestRadixTree_FindLongestPrefix(t *testing.T) {
	tree := NewRadixTree()
	handler := func(ctx *fasthttp.RequestCtx) {}

	tree.Insert("/", handler, 1, "prefix", false)
	tree.Insert("/api", handler, 2, "prefix", false)
	tree.Insert("/api/v1", handler, 3, "prefix", false)

	// "/" has priority 1 (wins), "/api" has 2, "/api/v1" has 3
	// Lower number = higher priority
	result := tree.FindLongestPrefix([]byte("/api/v1/users"))
	if result == nil {
		t.Fatal("expected match")
	}
	if result.Path != "/" {
		t.Errorf("expected / (priority 1 wins), got %s", result.Path)
	}
}

func TestRadixTree_Insert_AfterInitialized(t *testing.T) {
	tree := NewRadixTree()
	handler := func(ctx *fasthttp.RequestCtx) {}

	tree.Insert("/api", handler, 1, "prefix", false)
	tree.MarkInitialized()

	err := tree.Insert("/api/v2", handler, 2, "prefix", false)
	if err == nil {
		t.Error("should fail when inserting after initialized")
	}
}

func TestRadixTree_Insert_DuplicatePath(t *testing.T) {
	tree := NewRadixTree()
	handler := func(ctx *fasthttp.RequestCtx) {}

	tree.Insert("/api", handler, 1, "prefix", false)
	err := tree.Insert("/api", handler, 2, "prefix", false)
	if err == nil {
		t.Error("should fail on duplicate path")
	}
}

func TestRadixTree_FindLongestPrefix_NoMatch(t *testing.T) {
	tree := NewRadixTree()
	handler := func(ctx *fasthttp.RequestCtx) {}

	tree.Insert("/api", handler, 1, "prefix", false)

	result := tree.FindLongestPrefix([]byte("/other"))
	if result != nil {
		t.Errorf("expected nil for no match, got %+v", result)
	}
}

func TestRadixTree_PriorityComparison(t *testing.T) {
	tree := NewRadixTree()
	h1 := func(ctx *fasthttp.RequestCtx) {}
	h2 := func(ctx *fasthttp.RequestCtx) {}

	tree.Insert("/api", h1, 5, "prefix", false)
	tree.Insert("/api/users", h2, 2, "prefix", false)

	// Lower priority number wins
	result := tree.FindLongestPrefix([]byte("/api/users"))
	if result == nil {
		t.Fatal("expected match")
	}
	if result.Priority != 2 {
		t.Errorf("expected priority 2, got %d", result.Priority)
	}
}

func TestRadixTree_Insert_ExactMatch(t *testing.T) {
	// Case 3: path 完全匹配节点前缀，设置 handler
	tree := NewRadixTree()
	handler := func(ctx *fasthttp.RequestCtx) { ctx.SetBodyString("exact") }

	// 先插入父路径
	tree.Insert("/api", handler, 1, "prefix", false)

	// 再次插入相同路径（应该报错重复）
	err := tree.Insert("/api", handler, 2, "prefix", false)
	if err == nil {
		t.Error("should return error for duplicate path")
	}

	// 验证原 handler 未被覆盖
	result := tree.FindLongestPrefix([]byte("/api"))
	if result == nil || result.Priority != 1 {
		t.Errorf("original handler should not be overwritten, got priority %d", result.Priority)
	}
}
