package core

import (
	"testing"
	"time"
)

func TestActionCreate(t *testing.T) {
	db := EphemeralDb(t)

	if err := AddAction(db, "test", "hello", []string{"echo", "hello"}); err == nil {
		t.Fatal("Action created for nonexistent source")
	}

	if err := AddSource(db, "test"); err != nil {
		t.Fatal(err)
	}

	if err := AddAction(db, "test", "hello", []string{"echo", "hello"}); err != nil {
		t.Fatal(err)
	}
	if err := AddAction(db, "test", "goodbye", []string{"exit", "1"}); err != nil {
		t.Fatal(err)
	}
	if err := UpdateAction(db, "test", "goodbye", []string{"echo", "goodbye"}); err != nil {
		t.Fatal(err)
	}

	actions, err := GetActionsForSource(db, "test")
	if err != nil {
		t.Fatal(err)
	}
	if len(actions) != 2 {
		t.Fatal("expected 2 actions")
	}
	found := make(map[string]bool)
	for _, action := range actions {
		found[action] = true
	}
	if !found["hello"] || !found["goodbye"] {
		t.Fatalf("missing hello and/or goodbye, got: %v", actions)
	}

	argv, err := GetArgvForAction(db, "test", "goodbye")
	if err != nil {
		t.Fatal(err)
	}
	if len(argv) != 2 || argv[0] != "echo" || argv[1] != "goodbye" {
		t.Fatalf("expected [echo goodbye], got: %v", argv)
	}

	err = DeleteAction(db, "test", "hello")
	if err != nil {
		t.Fatal(err)
	}
}

func TestExecute(t *testing.T) {
	assertLen := func(items []Item, length int) {
		if len(items) != length {
			t.Fatalf("Expected %d items, got %d", length, len(items))
		}
	}
	assertNil := func(err error) {
		if err != nil {
			t.Fatal(err)
		}
	}
	assertNotNil := func(err error) {
		if err == nil {
			t.Fatal("expected err")
		}
	}

	res, err := Execute(
		"",
		[]string{"true"},
		nil,
		"",
		time.Minute,
	)
	assertNil(err)
	assertLen(res, 0)

	// Exit with error code
	res, err = Execute(
		"",
		[]string{"false"},
		nil,
		"",
		time.Minute,
	)
	assertNotNil(err)
	assertLen(res, 0)

	res, err = Execute(
		"",
		[]string{"sh", "-c", "exit 22"},
		nil,
		"",
		time.Minute,
	)
	assertNotNil(err)
	assertLen(res, 0)

	// Timeout
	res, err = Execute(
		"",
		[]string{"sleep", "10"},
		nil,
		"",
		time.Millisecond,
	)
	assertNotNil(err)
	assertLen(res, 0)

	// Returning items
	res, err = Execute(
		"",
		[]string{"jq", "-cn", `{id: "foo"}`},
		nil,
		"",
		time.Minute,
	)
	assertNil(err)
	assertLen(res, 1)
	if res[0].Id != "foo" {
		t.Fatal("jq -cn test failed")
	}

	// Read from stdin
	res, err = Execute(
		"",
		[]string{"jq", "-cR", `{id: .}`},
		nil,
		"bar",
		time.Minute,
	)
	assertNil(err)
	assertLen(res, 1)
	if res[0].Id != "bar" {
		t.Fatal("jq -cR test failed")
	}

	// Set env
	res, err = Execute(
		"",
		[]string{"jq", "-cn", `{id: env.HELLO}`},
		[]string{"HELLO=baz"},
		"",
		time.Minute,
	)
	assertNil(err)
	assertLen(res, 1)
	if res[0].Id != "baz" {
		t.Fatal("jq -cn env test failed")
	}

	// With logging on stderr
	res, err = Execute(
		"",
		[]string{"sh", "-c", `echo 1>&2 Hello; jq -cn '{id: "box"}'; echo 1>&2 World`},
		nil,
		"",
		time.Minute,
	)
	assertNil(err)
	assertLen(res, 1)
	if res[0].Id != "box" {
		t.Fatal("stderr test failed")
	}
}