package emote_test

import (
	"strings"
	"testing"

	"git.sunturtle.xyz/zephyr/kaiyan/emote"
	"github.com/google/go-cmp/cmp"
)

func TestParser(t *testing.T) {
	cases := []struct {
		name   string
		emotes []string
		text   string
		want   []string
	}{
		{
			name:   "empty",
			emotes: strings.Fields("bocchi ryō nijika kita"),
			text:   "",
			want:   nil,
		},
		{
			name:   "none",
			emotes: nil,
			text:   "bocchi ryō nijika kita",
			want:   nil,
		},
		{
			name:   "all",
			emotes: strings.Fields("bocchi ryō nijika kita"),
			text:   "bocchi ryō nijika kita",
			want:   strings.Fields("bocchi ryō nijika kita"),
		},
		{
			name:   "some",
			emotes: strings.Fields("bocchi nijika"),
			text:   "bocchi ryō nijika kita",
			want:   strings.Fields("bocchi nijika"),
		},
		{
			name:   "others",
			emotes: strings.Fields("ryō kita"),
			text:   "bocchi ryō nijika kita",
			want:   strings.Fields("ryō kita"),
		},
	}
	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			// Convert the emote names to emotes proper.
			e := make([]emote.Emote, len(c.emotes))
			for i, w := range c.emotes {
				e[i] = emote.Emote{ID: w, Name: w, Source: c.name}
			}
			p := emote.NewParser(e...)
			var got []string
			text := c.text
			for {
				em, rest := p.Next(text)
				if em.ID == "" {
					break
				}
				if em.Name != em.ID {
					// Not normally the case, but this test is constructed
					// so that it is.
					t.Errorf("wrong id %q for name %q", em.ID, em.Name)
				}
				got = append(got, em.Name)
				text = rest
			}
			if diff := cmp.Diff(c.want, got); diff != "" {
				t.Errorf("wrong emotes (-want/+got):\n%s", diff)
			}
		})
	}
}

func BenchmarkParser(b *testing.B) {
	e := []emote.Emote{
		{ID: "bocchi", Name: "bocchi"},
		{ID: "ryō", Name: "ryō"},
		{ID: "nijika", Name: "nijika"},
		{ID: "kita", Name: "kita"},
		{ID: "seika", Name: "seika"},
		{ID: "kikuri", Name: "kikuri"},
		{ID: "eliza", Name: "eliza"},
		{ID: "shima", Name: "shima"},
	}
	p := emote.NewParser(e...)
	texts := []struct {
		name string
		text string
	}{
		{"none-short", "none"},
		{"none-long", strings.TrimSpace(strings.Repeat("none ", 100))},
		{"single", "bocchi"},
		{"natural", strings.TrimSpace(strings.Repeat("kessoku band is bocchi ryō nijika kita starry is seika PA-san sickhack is kikuri eliza shima ", 5))},
	}
	for _, c := range texts {
		b.Run(c.name, func(b *testing.B) {
			b.SetBytes(int64(len(c.text)))
			for b.Loop() {
				text := c.text
				for text != "" {
					_, text = p.Next(text)
				}
			}
		})
	}
}