package urlrewrite

import (
	"encoding/json"
	"reflect"
	"testing"
)

func TestRewriteStringValue(t *testing.T) {
	oldPrefix := "https://s3.jizhying.com/images/"
	newPrefix := "https://dp9pkdckmd09t.cloudfront.net/"

	tests := []struct {
		name  string
		input string
		want  string
	}{
		{
			name:  "replace matching prefix",
			input: "https://s3.jizhying.com/images/openim/data/hash/a.jpg",
			want:  "https://dp9pkdckmd09t.cloudfront.net/openim/data/hash/a.jpg",
		},
		{
			name:  "keep non matching url",
			input: "https://example.com/a.jpg",
			want:  "https://example.com/a.jpg",
		},
		{
			name:  "keep plain text",
			input: "hello",
			want:  "hello",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, changed := rewriteStringValue(tt.input, oldPrefix, newPrefix)
			if got != tt.want {
				t.Fatalf("rewriteStringValue() = %q, want %q", got, tt.want)
			}
			if (tt.input != tt.want) != changed {
				t.Fatalf("rewriteStringValue() changed = %v, want %v", changed, tt.input != tt.want)
			}
		})
	}
}

func TestRewriteJSONContent(t *testing.T) {
	oldPrefix := "https://s3.jizhying.com/images/"
	newPrefix := "https://dp9pkdckmd09t.cloudfront.net/"

	input := `{"sourcePicture":{"url":"https://s3.jizhying.com/images/openim/data/hash/src.jpg"},"snapshotPicture":{"url":"https://s3.jizhying.com/images/openim/data/hash/snap.jpg"},"nested":{"fileElem":{"sourceUrl":"https://s3.jizhying.com/images/openim/data/hash/file.zip"}}}`
	want := `{"nested":{"fileElem":{"sourceUrl":"https://dp9pkdckmd09t.cloudfront.net/openim/data/hash/file.zip"}},"snapshotPicture":{"url":"https://dp9pkdckmd09t.cloudfront.net/openim/data/hash/snap.jpg"},"sourcePicture":{"url":"https://dp9pkdckmd09t.cloudfront.net/openim/data/hash/src.jpg"}}`

	got, changed, err := rewriteJSONContent(input, oldPrefix, newPrefix)
	if err != nil {
		t.Fatalf("rewriteJSONContent() error = %v", err)
	}
	if !changed {
		t.Fatalf("rewriteJSONContent() changed = false, want true")
	}
	if got != want {
		t.Fatalf("rewriteJSONContent() = %s, want %s", got, want)
	}
}

func TestRewriteJSONContentNestedJSONString(t *testing.T) {
	oldPrefix := "https://s3.jizhying.com/images/"
	newPrefix := "https://dp9pkdckmd09t.cloudfront.net/"

	input := `{"detail":"{\"group\":{\"faceURL\":\"https://s3.jizhying.com/images/openim/data/hash/group.jpg\"},\"entrantUser\":{\"faceURL\":\"https://s3.jizhying.com/images/openim/data/hash/user.jpg\"}}"}`
	want := `{"detail":"{\"group\":{\"faceURL\":\"https://dp9pkdckmd09t.cloudfront.net/openim/data/hash/group.jpg\"},\"entrantUser\":{\"faceURL\":\"https://dp9pkdckmd09t.cloudfront.net/openim/data/hash/user.jpg\"}}"}`

	got, changed, err := rewriteJSONContent(input, oldPrefix, newPrefix)
	if err != nil {
		t.Fatalf("rewriteJSONContent() error = %v", err)
	}
	if !changed {
		t.Fatalf("rewriteJSONContent() changed = false, want true")
	}
	var gotValue map[string]any
	var wantValue map[string]any
	if err := json.Unmarshal([]byte(got), &gotValue); err != nil {
		t.Fatalf("unmarshal got error = %v", err)
	}
	if err := json.Unmarshal([]byte(want), &wantValue); err != nil {
		t.Fatalf("unmarshal want error = %v", err)
	}
	var gotDetail any
	var wantDetail any
	if err := json.Unmarshal([]byte(gotValue["detail"].(string)), &gotDetail); err != nil {
		t.Fatalf("unmarshal got detail error = %v", err)
	}
	if err := json.Unmarshal([]byte(wantValue["detail"].(string)), &wantDetail); err != nil {
		t.Fatalf("unmarshal want detail error = %v", err)
	}
	gotValue["detail"] = gotDetail
	wantValue["detail"] = wantDetail
	if !reflect.DeepEqual(gotValue, wantValue) {
		t.Fatalf("rewriteJSONContent() = %#v, want %#v", gotValue, wantValue)
	}
}

func TestRewriteJSONContentInvalidJSON(t *testing.T) {
	_, changed, err := rewriteJSONContent("not-json", "https://old/", "https://new/")
	if err == nil {
		t.Fatalf("rewriteJSONContent() error = nil, want non-nil")
	}
	if changed {
		t.Fatalf("rewriteJSONContent() changed = true, want false")
	}
}

func TestCollectMsgFieldUpdates(t *testing.T) {
	oldPrefix := "https://s3.jizhying.com/images/"
	newPrefix := "https://dp9pkdckmd09t.cloudfront.net/"

	doc := msgDoc{
		Doc: "si_a_b:0",
		Msgs: []msgEntryModel{
			{
				Msg: &msgPayload{
					Content:       `{"sourcePicture":{"url":"https://s3.jizhying.com/images/openim/data/hash/1.jpg"}}`,
					SenderFaceURL: "https://s3.jizhying.com/images/openim/data/hash/avatar.jpg",
				},
			},
			{
				Msg: &msgPayload{
					Content:       `{"text":"hello"}`,
					SenderFaceURL: "",
				},
			},
		},
	}

	updates, changed, samples := collectMsgFieldUpdates(doc, oldPrefix, newPrefix, 5)
	if !changed {
		t.Fatalf("collectMsgFieldUpdates() changed = false, want true")
	}
	if len(samples) != 2 {
		t.Fatalf("collectMsgFieldUpdates() samples len = %d, want 2", len(samples))
	}
	if len(updates) != 2 {
		t.Fatalf("collectMsgFieldUpdates() updates len = %d, want 2", len(updates))
	}
	if updates[0].Path != "msgs.0.msg.content" {
		t.Fatalf("first update path = %s", updates[0].Path)
	}
	if updates[0].NewValue != `{"sourcePicture":{"url":"https://dp9pkdckmd09t.cloudfront.net/openim/data/hash/1.jpg"}}` {
		t.Fatalf("content update = %s", updates[0].NewValue)
	}
	if updates[1].Path != "msgs.0.msg.sender_face_url" {
		t.Fatalf("second update path = %s", updates[1].Path)
	}
	if updates[1].NewValue != "https://dp9pkdckmd09t.cloudfront.net/openim/data/hash/avatar.jpg" {
		t.Fatalf("sender_face_url update = %s", updates[1].NewValue)
	}
}

func TestBuildBackupDocs(t *testing.T) {
	updates := []fieldUpdate{
		{Path: "face_url", OldValue: "https://old/a.jpg", NewValue: "https://new/a.jpg"},
		{Path: "thumbnail", OldValue: "https://old/b.jpg", NewValue: "https://new/b.jpg"},
	}

	docs := buildBackupDocs("batch-1", "attributes", "doc-1", updates)
	if len(docs) != 2 {
		t.Fatalf("buildBackupDocs() len = %d, want 2", len(docs))
	}
}
