package entity

import (
	"fmt"
	"testing"

	"go.mongodb.org/mongo-driver/bson"
)

func TestOne(t *testing.T) {
	one := One{
		Name: "myname",
		Type: "mytype",
	}
	q := one.Query()
	if want := fmt.Sprint(One{Name: one.Name}); want != fmt.Sprint(q) {
		t.Error(want, q)
	}
}

func TestOneMarshalBSON(t *testing.T) {
	cases := map[string]struct {
		sameAsQuery bool
		one         One
	}{
		"query no modified change": {
			sameAsQuery: true,
			one:         (One{Name: "hello", Type: "world", Modified: 1}).Query(),
		},
		"modified changes": {
			one: One{Name: "hello", Type: "world", Modified: 1},
		},
		"w/ connections": {
			one: One{Name: "hello", Type: "world", Modified: 1, Connections: map[string]One{"hi": One{Name: "hi", Relationship: "mom"}}},
		},
		"w/ attachments": {
			one: One{Name: "hello", Type: "world", Modified: 1, Attachments: map[string]string{"hello": "/world"}},
		},
	}

	for name, d := range cases {
		c := d
		t.Run(name, func(t *testing.T) {
			var bm bson.Marshaler = c.one
			t.Log(bm)
			b, err := bson.Marshal(c.one)
			if err != nil {
				t.Fatal(err)
			}
			one := One{}
			if err := bson.Unmarshal(b, &one); err != nil {
				t.Fatal(err)
			}
			if c.sameAsQuery && (fmt.Sprint(one) != fmt.Sprint(one.Query()) || fmt.Sprint(one) != fmt.Sprint(c.one)) {
				t.Error(c.sameAsQuery, c.one, one)
			} else if !c.sameAsQuery {
				if c.one.Modified == one.Modified {
					t.Error(c.one.Modified, one.Modified)
				}
				c.one.Modified = 0
				one.Modified = 0
				for k := range one.Connections {
					temp := one.Connections[k]
					temp.Modified = 0
					one.Connections[k] = temp
				}
				if fmt.Sprint(c.one) != fmt.Sprint(one) {
					t.Error(c.one, one)
				}
			}
		})
	}
}

func TestOneMarshalBSONBadConnections(t *testing.T) {
	t.Run("connections has an empty string for a key that should die", func(t *testing.T) {
		input := One{Name: "hello", Connections: map[string]One{"": One{Name: "teehee"}}}

		b, err := bson.Marshal(input)
		if err != nil {
			t.Fatal(err)
		}

		output := One{}
		if err := bson.Unmarshal(b, &output); err != nil {
			t.Fatal(err)
		}

		if len(output.Connections) != 0 {
			t.Fatal(output.Connections)
		}

		input.Connections = nil
		output.Connections = nil
		input.Modified = 0
		output.Modified = 0

		if fmt.Sprint(input) != fmt.Sprint(output) {
			t.Fatal(input, output)
		}
	})

	t.Run("connections has a key but empty name that should correct", func(t *testing.T) {
		input := One{Name: "hello", Connections: map[string]One{"teehee": One{Name: ""}}}

		b, err := bson.Marshal(input)
		if err != nil {
			t.Fatal(err)
		}

		output := One{}
		if err := bson.Unmarshal(b, &output); err != nil {
			t.Fatal(err)
		}

		if len(output.Connections) != 1 {
			t.Fatal(output.Connections)
		} else {
			for k := range output.Connections {
				if k != output.Connections[k].Name {
					t.Fatal(k, output.Connections)
				}
			}
		}

		input.Connections = nil
		output.Connections = nil
		input.Modified = 0
		output.Modified = 0

		if fmt.Sprint(input) != fmt.Sprint(output) {
			t.Fatal(input, output)
		}
	})
}
