package runtimeevents

import (
	"strings"
	"testing"
)

func TestScrubUsageTokensData(t *testing.T) {
	ev := NewDataEvent(NewUsageTokensData("sk-secret-123", 100, 50, 200, 0))

	out := ScrubEvent(ev)
	d, ok := DataAs[*UsageTokensData](out)
	if !ok {
		t.Fatal("DataAs[*UsageTokensData] failed")
	}
	if d.APIKey != "***" {
		t.Errorf("APIKey not redacted: %q", d.APIKey)
	}
	if d.InputTokens != 100 {
		t.Errorf("InputTokens changed: %d", d.InputTokens)
	}
}

func TestScrubTurnTextDataTruncation(t *testing.T) {
	longText := strings.Repeat("x", 3000)
	ev := NewDataEvent(NewTurnTextData(KindTurnText, longText))

	out := ScrubEvent(ev)
	d, ok := DataAs[*TurnTextData](out)
	if !ok {
		t.Fatal("DataAs[*TurnTextData] failed")
	}
	if len(d.Text) > maxTextLen {
		t.Errorf("Text not truncated: len=%d, max=%d", len(d.Text), maxTextLen)
	}
}

func TestScrubToolCallDataPreservesLongInput(t *testing.T) {
	longInput := strings.Repeat("a", 3000)
	ev := NewDataEvent(NewToolCallData("test_tool", longInput))

	out := ScrubEvent(ev)
	d, ok := DataAs[*ToolCallData](out)
	if !ok {
		t.Fatal("DataAs[*ToolCallData] failed")
	}
	if d.ToolInput != longInput {
		t.Errorf("ToolInput changed: len=%d", len(d.ToolInput))
	}
}

func TestScrubToolCallDataRedactsJSONSensitiveKeysWithoutTruncating(t *testing.T) {
	longContent := strings.Repeat("a", 3000)
	input := `{"content":"` + longContent + `","api_key":"sk-secret","nested":{"Authorization":"Bearer token"}}`
	ev := NewDataEvent(NewToolCallData("test_tool", input))

	out := ScrubEvent(ev)
	d, ok := DataAs[*ToolCallData](out)
	if !ok {
		t.Fatal("DataAs[*ToolCallData] failed")
	}
	if !strings.Contains(d.ToolInput, longContent) {
		t.Error("ToolInput content was truncated")
	}
	if strings.Contains(d.ToolInput, "sk-secret") || strings.Contains(d.ToolInput, "Bearer token") {
		t.Errorf("ToolInput sensitive values were not redacted: %s", d.ToolInput)
	}
	if !strings.Contains(d.ToolInput, `"api_key":"***"`) || !strings.Contains(d.ToolInput, `"Authorization":"***"`) {
		t.Errorf("ToolInput redactions missing: %s", d.ToolInput)
	}
}

func TestScrubMapDataSensitiveKeys(t *testing.T) {
	ev := NewEvent(KindSessionStarted, WithMapData(KindSessionStarted, map[string]any{
		"api_key":       "sk-secret-123",
		"Authorization": "Bearer token",
		"normal_field":  "visible",
	}))

	out := ScrubEvent(ev)
	d, ok := DataAs[*MapData](out)
	if !ok {
		t.Fatal("DataAs[*MapData] failed")
	}
	if d.Map["api_key"] != "***" {
		t.Errorf("api_key not redacted: %v", d.Map["api_key"])
	}
	if d.Map["Authorization"] != "***" {
		t.Errorf("Authorization not redacted: %v", d.Map["Authorization"])
	}
	if d.Map["normal_field"] != "visible" {
		t.Errorf("normal_field should be preserved, got %v", d.Map["normal_field"])
	}
}

func TestScrubEventOriginalNotModified(t *testing.T) {
	ev := NewDataEvent(NewUsageTokensData("sk-original", 10, 0, 20, 0))

	_ = ScrubEvent(ev)

	d, ok := DataAs[*UsageTokensData](ev)
	if !ok {
		t.Fatal("DataAs failed")
	}
	if d.APIKey != "sk-original" {
		t.Errorf("original modified: %q", d.APIKey)
	}
}

func TestScrubEventNoData(t *testing.T) {
	ev := NewEvent(KindSessionStarted)
	out := ScrubEvent(ev)
	if out.Data != nil {
		t.Errorf("expected nil Data, got %v", out.Data)
	}
}

func TestDataAsWrongType(t *testing.T) {
	ev := NewDataEvent(NewWakeData(KindWakeReceived, "test"))

	_, ok := DataAs[*UsageTokensData](ev)
	if ok {
		t.Error("DataAs[*UsageTokensData] should fail for WakeData")
	}
}
