package redis_test

import (
	"context"
	"fmt"
	"os"
	"reflect"
	"testing"
	"time"

	"gitlab.com/uafrica/go-utils/redis"
)

func TestString(t *testing.T) {
	os.Setenv("REDIS_HOST", "localhost")
	os.Setenv("REDIS_PORT", "6380")
	ctx := context.Background()
	r, err := redis.New(ctx)
	if err != nil {
		t.Fatalf("failed to create redis: %+v", err)
	}
	id := fmt.Sprintf("%s_%v", t.Name(), time.Now().Unix())
	defer func() {
		r.Del(id)
	}()

	value := "abc123"
	if err := r.SetString(id, value); err != nil {
		t.Fatalf("failed to set: (%T) %+v", err, err)
	}

	//get after set must return same value
	if v, ok := r.GetString(id); !ok {
		t.Fatalf("failed to get(%s)", id)
	} else {
		if v != value {
			t.Fatalf("%s=%s != %s", id, v, value)
		}
	}

	//must be able to delete
	if err := r.Del(id); err != nil {
		t.Fatalf("failed to del(%s): %+v", id, err)
	}

	//delete non-existing must also succeed
	if err := r.Del(id); err != nil {
		t.Fatalf("failed to del(%s) again: %+v", id, err)
	}

	//get after delete must indicate not exist
	if _, ok := r.GetString(id); ok {
		t.Fatalf("got(%s) after delete", id)
	}
}

func TestJSON(t *testing.T) {
	os.Setenv("REDIS_HOST", "localhost")
	os.Setenv("REDIS_PORT", "6380")
	ctx := context.Background()
	r, err := redis.New(ctx)
	if err != nil {
		t.Fatalf("failed to create redis: %+v", err)
	}
	id := fmt.Sprintf("%s_%v", t.Name(), time.Now().Unix())
	defer func() {
		r.Del(id)
	}()

	type Person struct {
		Name    string    `json:"name"`
		Surname string    `json:"surname"`
		Count   int       `json:"count"`
		Dob     time.Time `json:"dob"`
	}
	dob, err := time.Parse("2006-01-02", "1986-06-28")
	if err != nil {
		t.Fatalf("invalid dob: %+v", err)
	}
	value := Person{"Joe", "Blogs", 25, dob}
	if err := r.SetJSON(id, value); err != nil {
		t.Fatalf("failed to set: (%T) %+v", err, err)
	}

	//get after set must return same value
	if v, ok := r.GetJSON(id, reflect.TypeOf(Person{})); !ok {
		t.Fatalf("failed to get(%s): %+v", id, err)
	} else {
		if v != value {
			t.Fatalf("%s=%+v != %+v", id, v, value)
		}
	}

	//must be able to delete
	if err := r.Del(id); err != nil {
		t.Fatalf("failed to del(%s): %+v", id, err)
	}

	//delete non-existing must also succeed
	if err := r.Del(id); err != nil {
		t.Fatalf("failed to del(%s) again: %+v", id, err)
	}

	//get after delete must indicate not exist
	if v, ok := r.GetJSON(id, reflect.TypeOf(Person{})); ok {
		t.Fatalf("got(%s) after delete: %+v", id, v)
	}
}

func TestExp(t *testing.T) {
	os.Setenv("REDIS_HOST", "localhost")
	os.Setenv("REDIS_PORT", "6380")
	ctx := context.Background()
	r, err := redis.New(ctx)
	if err != nil {
		t.Fatalf("failed to create redis: %+v", err)
	}
	id := fmt.Sprintf("%s_%v", t.Name(), time.Now().Unix())
	defer func() {
		r.Del(id)
	}()

	value := "abc123"
	if err := r.SetStringForDur(id, value, time.Second); err != nil {
		t.Fatalf("failed to set: (%T) %+v", err, err)
	}

	//get after set must return same value
	if v, ok := r.GetString(id); !ok {
		t.Fatalf("failed to get(%s)", id)
	} else {
		if v != value {
			t.Fatalf("%s=%s != %s", id, v, value)
		}
	}

	//wait 5 seconds
	t.Logf("waiting 5seconds for key to expire...")
	time.Sleep(time.Second * 5)

	//get after delete expire must fail
	if _, ok := r.GetString(id); ok {
		t.Fatalf("got(%s) after expiry", id)
	}
}