// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package wrap

import (
	"encoding/json"
	"fmt"
	"testing"

	"github.com/google/go-cmp/cmp"
	"golang.org/x/oscar/internal/storage"
)

func TestWrapper(t *testing.T) {
	w := New("test-bot", "test")
	body := "this is a comment"
	metadata := &struct {
		Foo string
		Bar int
	}{
		Foo: "foo",
		Bar: 123,
	}

	for _, tc := range []struct {
		name     string
		body     string
		meta     any
		wantMeta json.RawMessage
	}{
		{
			name:     "no_metadata",
			body:     body,
			meta:     nil,
			wantMeta: nil,
		},
		{
			name:     "metadata",
			body:     body,
			meta:     metadata,
			wantMeta: storage.JSON(metadata),
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			wrapped, err := w.Wrap(tc.body, tc.meta)
			if err != nil {
				t.Fatal(err)
			}
			wrappedEdit := "something" + wrapped + "something else"

			t.Run("IsWrapped", func(t *testing.T) {
				if !Is(wrapped) {
					t.Errorf("IsWrapped(%s, nil) = false, want true", wrapped)
				}

				// IsWrapped expects an an exact match.
				if Is(wrappedEdit) {
					t.Errorf("IsWrapped(%s) = true, want false", wrappedEdit)
				}
			})

			t.Run("ContainsWrapped", func(t *testing.T) {
				if !Contains(wrapped) {
					t.Errorf("ContainsWrapped(%s, nil) = false, want true", wrapped)
				}

				if !Contains(wrappedEdit) {
					t.Errorf("ContainsWrapped(%s) = false, want true", wrappedEdit)
				}
			})

			t.Run("Parse", func(t *testing.T) {
				got := Parse(wrapped)
				if got == nil {
					t.Fatalf("Parse(%s) = nil, want non-nil", wrapped)
				}
				if got.Body != body {
					t.Errorf("Parse(%s).Body = %q, want %q", wrapped, got.Body, body)
				}
				if string(got.Meta) != string(tc.wantMeta) {
					t.Errorf("Parse(%s).Metadata = %q, want %s", wrapped, got.Meta, tc.wantMeta)
				}
			})

			t.Run("ParseAll", func(t *testing.T) {
				wrappedMultiple := "something" + wrapped + "something else" + wrapped
				got := ParseAll(wrappedMultiple)
				want := []*Unwrapped{
					{
						TagContent: TagContent{
							Bot:  "test-bot",
							Kind: "test",
							Meta: tc.wantMeta,
						},
						Body: body,
					},
					{
						TagContent: TagContent{
							Bot:  "test-bot",
							Kind: "test",
							Meta: tc.wantMeta,
						},
						Body: body,
					},
				}
				if diff := cmp.Diff(want, got); diff != "" {
					t.Errorf("ParseAll(%s) mismatch (-want +got):\n%s", wrappedMultiple, diff)
				}
			})

			t.Run("Strip", func(t *testing.T) {
				wrappedMultiple := "something" + wrapped + " something else" + wrapped
				want := "something something else"
				got := Strip(wrappedMultiple)
				if got != want {
					t.Errorf("Strip(%s) = %v, want %v", wrappedMultiple, got, want)
				}
			})
		})
	}
}

func TestWrapperError(t *testing.T) {
	w := New("test-bot", "test")

	wrapped, err := w.Wrap("body <!-- oscar-end --> something", nil)
	if err == nil {
		t.Errorf("w.Wrap() = (%s, nil), want error", wrapped)
	}

	inner, err := w.Wrap("body", nil)
	if err != nil {
		t.Fatal(err)
	}

	// Can't double-wrap.
	double, err := w.Wrap(inner, nil)
	if err == nil {
		t.Errorf("w.Wrap() = (%s, nil), want error", double)
	}
}

func TestWrapperLiteral(t *testing.T) {
	// Full text by Oscar.
	comment :=
		`<!-- Generated by Oscar. DO NOT EDIT. {"bot":"test-bot","kind":"test","meta":{"Foo":"foo","Bar":123}} -->this is a comment
with multiple lines <!-- and an HTML comment --><!-- oscar-end -->`

	t.Run("IsWrapped", func(t *testing.T) {
		if !Is(comment) {
			t.Errorf("IsWrapped(%s) = false, want true", comment)
		}
	})

	t.Run("ContainsWrapped", func(t *testing.T) {
		edit := `hello` + comment + `some more stuff`
		if !Contains(edit) {
			t.Errorf("ContainsWrapped(%s) = false, want true", edit)
		}
	})

	t.Run("Parse", func(t *testing.T) {
		got := Parse(comment)
		if got == nil {
			t.Fatalf("Parse(%s) = nil, want non-nil", comment)
		}
		want := &Unwrapped{
			TagContent: TagContent{
				Bot:  "test-bot",
				Kind: "test",
				Meta: json.RawMessage(`{"Foo":"foo","Bar":123}`),
			},
			Body: `this is a comment
with multiple lines <!-- and an HTML comment -->`,
		}
		if !cmp.Equal(got, want) {
			t.Errorf("Parse(%s) = %+v, want %+v", comment, got, want)
		}
	})

	// Text with multiple edits by Oscar (with different bots and kinds).
	edited := `a user comment<!-- Generated by Oscar. DO NOT EDIT. {"bot":"test-bot","kind":"test","meta":{"Object:":{"Foo":"foo","Bar":123}}} -->this is a comment<!-- oscar-end -->
more user comment<!-- Generated by Oscar. DO NOT EDIT. {"bot":"test-bot2","kind":"test2","meta":{"Text":"hello"}} -->this is another comment<!-- oscar-end -->`
	t.Run("ParseAll", func(t *testing.T) {
		got := ParseAll(edited)
		want := []*Unwrapped{
			{
				TagContent: TagContent{
					Bot:  "test-bot",
					Kind: "test",
					Meta: json.RawMessage(`{"Object:":{"Foo":"foo","Bar":123}}`),
				},
				Body: `this is a comment`,
			},
			{
				TagContent: TagContent{
					Bot:  "test-bot2",
					Kind: "test2",
					Meta: json.RawMessage(`{"Text":"hello"}`),
				},
				Body: `this is another comment`,
			},
		}
		if diff := cmp.Diff(want, got); diff != "" {
			t.Errorf("ParseAll(%s) mismatch (-want +got):\n%s", comment, diff)
		}
	})

	t.Run("Strip", func(t *testing.T) {
		got := Strip(edited)
		want := `a user comment
more user comment`
		if got != want {
			t.Errorf("Strip(%s) = %s, want %s", edited, got, want)
		}
	})
}

func ExampleWrapper() {
	w := New("test-bot", "test")
	metadata := &struct {
		Foo string
		Bar int
	}{
		Foo: "foo",
		Bar: 123,
	}

	wrapped, err := w.Wrap("this is a comment", metadata)
	if err != nil {
		fmt.Println("Wrap:", err)
		return
	}
	fmt.Println("Wrap:", wrapped)

	isWrapped := Is(wrapped)
	fmt.Println("IsWrapped:", isWrapped)

	u := Parse(wrapped)
	fmt.Printf("Parse: (bot=%s, kind=%s, meta=%s, body=%s)\n", u.Bot, u.Kind, u.Meta, u.Body)

	// Output:
	// Wrap: <!-- Generated by Oscar. DO NOT EDIT. {"bot":"test-bot","kind":"test","meta":{"Foo":"foo","Bar":123}} -->this is a comment<!-- oscar-end -->
	// IsWrapped: true
	// Parse: (bot=test-bot, kind=test, meta={"Foo":"foo","Bar":123}, body=this is a comment)
}
