package etcd_tools

import (
	"fmt"
	"testing"
	"time"

	etcd "github.com/coreos/etcd/clientv3"
)

var s5 = 5 * time.Second

func DeleteAll(t *testing.T, q *Queue) {
	_, err := q.cli.Delete(q.prefix, etcd.WithPrefix())
	if err != nil {
		t.Fatal(err)
	}
}

func TestQueue(t *testing.T) {
	cli, err := NewLocalClient()
	if err != nil {
		t.Fatal(err)
	}
	defer cli.Close()
	q := NewQueue(cli, "foo")
	DeleteAll(t, q)
	_, err = q.Put("bar1")
	if err != nil {
		t.Fatal(err)
	}
	_, err = q.Put("bar2")
	if err != nil {
		t.Fatal(err)
	}
	pairs, err := q.Poll()
	if err != nil {
		t.Fatal(err)
	}
	for _, ev := range pairs {
		_, _ = cli.Delete(string(ev.Key))
	}
	if len(pairs) != 2 {
		t.Fatal("Wrong queue count.")
	}
	if pairs[0].Value != "bar1" {
		t.Fatal("Wrong first element.")
	}
	if pairs[1].Value != "bar2" {
		t.Fatal("Wrong first element.")
	}
	DeleteAll(t, q)
	_, err = q.PutWithTTL("snafu", 5)
	if err != nil {
		t.Fatal(err)
	}
	time.Sleep(6 * time.Second)
	pairs, err = q.Poll()
	if err != nil {
		t.Fatal(err)
	}
	if len(pairs) != 0 {
		t.Fatal(fmt.Sprintf("Queue item with ttl did not time out. %s", pairs[0].Value))
	}
}

func TestMove(t *testing.T) {
	cli, err := NewLocalClient()
	if err != nil {
		t.Fatal(err)
	}
	defer cli.Close()
	q1 := NewQueue(cli, "fubar")
	q2 := NewQueue(cli, "bar")
	DeleteAll(t, q1)
	DeleteAll(t, q2)
	_, err = q1.Put("baz")
	if err != nil {
		t.Fatal(err)
	}
	pairs, err := q1.Poll()
	if err != nil {
		t.Fatal(err)
	}
	if len(pairs) != 1 {
		t.Fatal("Wrong queue count.")
	}
	err = q1.Move(pairs[0], q2)
	if err != nil {
		t.Fatal(err)
	}
	pairs, err = q1.Poll()
	if err != nil {
		t.Fatal(err)
	}
	if len(pairs) != 0 {
		t.Fatal("Wrong q1 count.", pairs)
	}
	pairs, err = q2.Poll()
	if err != nil {
		t.Fatal(err)
	}
	if len(pairs) != 1 {
		t.Fatal("Wrong q2 count.")
	}
	if string(pairs[0].Value) != "baz" {
		t.Fatal("Wrong value after move.")
	}
	DeleteAll(t, q1)
	DeleteAll(t, q2)
	_, err = q1.Put("baz")
	if err != nil {
		t.Fatal(err)
	}
	pairs, err = q1.Poll()
	if err != nil {
		t.Fatal(err)
	}
	err = q1.MoveWithTTL(pairs[0], q2, 5)
	if err != nil {
		t.Fatal(err)
	}
	time.Sleep(6 * time.Second)
	pairs, err = q1.Poll()
	if err != nil {
		t.Fatal(err)
	}
	if len(pairs) != 0 {
		t.Fatal("Moved item with ttl did not time out.")
	}
}

func TestWatch(t *testing.T) {
	cli, err := NewLocalClient()
	if err != nil {
		t.Fatal(err)
	}
	q := NewQueue(cli, "pre")
	DeleteAll(t, q)
	_, _ = q.Put("one")
	_, _ = q.Put("two")
	_, _ = q.Put("three")
	ch := make(chan string)
	go func() {
		_ = q.Watch(func(q *Queue, kv *Pair) {
			ch <- kv.Value
		})
	}()
	x := <-ch
	if x != "one" {
		t.Fatal("Got wrong one")
	}
	x = <-ch
	if x != "two" {
		t.Fatal("Got wrong two")
	}
	x = <-ch
	if x != "three" {
		t.Fatal("Got wrong three")
	}
	DeleteAll(t, q)
	go func() {
		_ = q.Watch(func(q *Queue, kv *Pair) {
			ch <- kv.Value
		})
	}()
	_, _ = q.Put("foo")
	x = <-ch
	if x != "foo" {
		t.Fatal(fmt.Sprintf("Expected foo, got %s", x))
	}
	q.CancelWatch()
}
