package pttodo

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

	yaml "gopkg.in/yaml.v2"
)

func TestJSONTodo(t *testing.T) {
	todo := func() Todo {
		return Todo{
			Todo:     "todo",
			Details:  "detail",
			TS:       TS(1),
			Schedule: Schedule("schedule"),
		}
	}

	t.Run("marshal+unmarshal nonzero", func(t *testing.T) {
		todo := todo()
		todo.TS = 1
		var todo2 Todo
		if b, err := json.Marshal(todo); err != nil {
			t.Fatal(err)
		} else if err := json.Unmarshal(b, &todo2); err != nil {
			t.Fatal(err)
		} else if fmt.Sprint(todo) != fmt.Sprint(todo2) {
			t.Fatal(todo2)
		}
	})

	t.Run("zero ts should marshal to nonzero", func(t *testing.T) {
		todo := todo()
		todo.TS = 0
		var todo2 Todo
		if b, err := json.Marshal(todo); err != nil {
			t.Fatal(err)
		} else if err := json.Unmarshal(b, &todo2); err != nil {
			t.Fatal(err)
		} else if todo.TS == todo2.TS {
			t.Fatal(todo2)
		}
	})
}

func TestTodoUnmarshalYAML(t *testing.T) {
	t.Run("just a string", func(t *testing.T) {
		var littleRoot struct {
			Todo Todo
		}
		if err := yaml.Unmarshal([]byte(`
todo: my full task here
   `), &littleRoot); err != nil {
			t.Fatal(err)
		}
		if littleRoot.Todo.Todo != "my full task here" {
			t.Fatal(littleRoot)
		}
	})

	t.Run("full struct", func(t *testing.T) {
		var littleRoot struct {
			Todo Todo
		}
		if err := yaml.Unmarshal([]byte(`
todo:
   todo: the todo part of my task
   details: whatever
   schedule: "* * * * *"
   `), &littleRoot); err != nil {
			t.Fatal(err)
		}
		if littleRoot.Todo.Todo != "the todo part of my task" {
			t.Fatal(littleRoot)
		}
		if littleRoot.Todo.Details != "whatever" {
			t.Fatal(littleRoot)
		}
		if littleRoot.Todo.Schedule != "* * * * *" {
			t.Fatal(littleRoot)
		}
	})
}

func TestMarshalTodo(t *testing.T) {
	t.Run(`empty should return ""`, func(t *testing.T) {
		var todo Todo
		if b, err := yaml.Marshal(Todo{}); err != nil {
			t.Fatal(err)
		} else if s := string(b); strings.TrimSpace(s) != `""` {
			t.Fatalf("%q", s)
		} else if err := yaml.Unmarshal(b, &todo); err != nil {
			t.Fatal(err)
		} else if todo.Todo != "" {
			t.Fatal(todo.Todo)
		}
	})

	t.Run(`just "a" should return a`, func(t *testing.T) {
		var todo Todo
		if b, err := yaml.Marshal(Todo{Todo: "a"}); err != nil {
			t.Fatal(err)
		} else if s := string(b); strings.TrimSpace(s) != `a` {
			t.Fatalf("%q", s)
		} else if err := yaml.Unmarshal(b, &todo); err != nil {
			t.Fatal(err)
		} else if todo.Todo != "a" {
			t.Fatal(todo.Todo)
		}
	})

	t.Run(`struct should return struct`, func(t *testing.T) {
		var todo Todo
		if b, err := yaml.Marshal(Todo{Todo: "a", Details: "b"}); err != nil {
			t.Fatal(err)
		} else if err := yaml.Unmarshal(b, &todo); err != nil {
			t.Fatal(err)
		} else if todo.Todo != "a" {
			t.Fatal(todo.Todo)
		} else if todo.Details != "b" {
			t.Fatal(todo.Details)
		}
	})
}
