package redis

import (
	"encoding/json"
	"strconv"
	"time"

	mock_redis "github.com/fiskerinc/cloud-services/pkg/redis/mock"

	"github.com/golang/mock/gomock"
	"github.com/gomodule/redigo/redis"
)

var pool Pool
var mockHashMap map[string]interface{}

type timeoutTestConn int

// GetMockPool returns the singleton pool (for mocking)
func GetMockPool() Pool {
	if pool != nil {
		return pool
	}

	pool = &redis.Pool{
		Dial: func() (redis.Conn, error) { return timeoutTestConn(0), nil },
	}

	return pool
}

// SetMockPool sets the redis pool (ideal for mocking)
func SetMockPool(p Pool) {
	pool = p
}

func (tc timeoutTestConn) Do(c string, d ...interface{}) (interface{}, error) {
	switch c {
	case "GET":
		return "XXXXX", nil
	case "DEL":
		return []byte(strconv.Itoa(len(d))), nil
	case "HSET":
		mockHashMap[d[0].(string)] = d[1:]
		return time.Duration(-1), nil
	case "HGET":
		payload, _ := json.Marshal("XXXXX")
		return payload, nil
	case "HGETALL", "EXEC", "SMEMBERS", "MGET":
		return []interface{}{}, nil
	case "SMISMEMBER":
		return []interface{}{"0", "1"}, nil
	}

	return time.Duration(-1), nil
}
func (tc timeoutTestConn) DoWithTimeout(timeout time.Duration, cmd string, args ...interface{}) (interface{}, error) {
	return timeout, nil
}

func (tc timeoutTestConn) Receive() (interface{}, error) {
	return time.Duration(-1), nil
}
func (tc timeoutTestConn) ReceiveWithTimeout(timeout time.Duration) (interface{}, error) {
	return timeout, nil
}

func (tc timeoutTestConn) Send(string, ...interface{}) error { return nil }
func (tc timeoutTestConn) Err() error                        { return nil }
func (tc timeoutTestConn) Close() error                      { return nil }
func (tc timeoutTestConn) Flush() error                      { return nil }

// MockRedisConnection creates a mock pool with mock connections
func MockRedisConnection() {
	mockPool()
	mockHashMap = make(map[string]interface{})
}

func mockPool() {
	pool = &redis.Pool{
		Dial: func() (redis.Conn, error) { return timeoutTestConn(0), nil },
	}
}

func InitMockPool(ctrl *gomock.Controller, mockClient redis.Conn) {
	mockPool := mock_redis.NewMockPool(ctrl)
	mockPool.EXPECT().Get().Return(mockClient)
	SetMockPool(mockPool)
}
