package matcher

import (
	"errors"
	"testing"

	"github.com/valyala/fasthttp"
)

// nginx priority: exact(=) > prefix_priority(^~) > regex(~) > prefix
func TestLocationEngine_NginxPriority(t *testing.T) {
	engine := NewLocationEngine()
	handler := func(ctx *fasthttp.RequestCtx) {}

	// 注册不同类型
	engine.AddExact("/api", handler, false)           // priority 1
	engine.AddPrefixPriority("/api/", handler, false) // priority 2 (^~)
	engine.AddRegex(`\.php$`, handler, false, false)  // priority 3
	engine.AddPrefix("/", handler, false)             // priority 4
	engine.MarkInitialized()

	// 测试精确匹配优先
	result := engine.Match([]byte("/api"))
	if result.LocationType != "exact" {
		t.Errorf("expected exact, got %s", result.LocationType)
	}

	// 测试 ^~ 阻止正则
	result = engine.Match([]byte("/api/test.php"))
	if result.LocationType != "prefix_priority" {
		t.Errorf("^~ should block regex, got %s", result.LocationType)
	}
}

func TestLocationEngine_RegexMatch(t *testing.T) {
	engine := NewLocationEngine()
	handler := func(ctx *fasthttp.RequestCtx) {}

	engine.AddPrefixPriority("/api/", handler, false)
	engine.AddRegex(`\.php$`, handler, false, false)
	engine.AddPrefix("/", handler, false)
	engine.MarkInitialized()

	// 正则匹配（^~ 不匹配 /index.php）
	result := engine.Match([]byte("/index.php"))
	if result.LocationType != "regex" {
		t.Errorf("expected regex for /index.php, got %s", result.LocationType)
	}
}

func TestLocationEngine_PrefixFallback(t *testing.T) {
	engine := NewLocationEngine()
	handler := func(ctx *fasthttp.RequestCtx) {}

	engine.AddPrefix("/", handler, false)
	engine.MarkInitialized()

	result := engine.Match([]byte("/any/path"))
	if result == nil || result.LocationType != "prefix" {
		t.Errorf("expected prefix match, got %v", result)
	}
}

func TestLocationEngine_NoMatch(t *testing.T) {
	engine := NewLocationEngine()
	engine.MarkInitialized()

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

func TestLocationEngine_RegexCaptures(t *testing.T) {
	engine := NewLocationEngine()
	handler := func(ctx *fasthttp.RequestCtx) {}

	engine.AddRegex(`^/user/(?P<id>[0-9]+)$`, handler, false, false)
	engine.MarkInitialized()

	result := engine.Match([]byte("/user/42"))
	if result.LocationType != "regex" {
		t.Errorf("expected regex, got %s", result.LocationType)
	}
	if result.Captures == nil || result.Captures["id"] != "42" {
		t.Errorf("expected captures id=42, got %v", result.Captures)
	}
}

func TestLocationEngine_Initialized_Twice(t *testing.T) {
	engine := NewLocationEngine()
	handler := func(ctx *fasthttp.RequestCtx) {}

	engine.MarkInitialized()

	err := engine.AddExact("/api", handler, false)
	if err == nil {
		t.Error("should fail when adding after initialized")
	}
}

func TestLocationEngine_PathConflict(t *testing.T) {
	engine := NewLocationEngine()
	handler := func(ctx *fasthttp.RequestCtx) {}

	engine.AddExact("/api", handler, false)
	err := engine.AddExact("/api", handler, false)
	if err == nil {
		t.Error("should fail on path conflict")
	}
	var ce *ConflictError
	if !errors.As(err, &ce) {
		t.Errorf("expected *ConflictError, got %T: %v", err, err)
	}
}
