package services

import (
	"sync"

	"github.com/fiskerinc/cloud-services/pkg/logger"
	"github.com/fiskerinc/cloud-services/pkg/redis"
	"github.com/pkg/errors"
)

var pubsub redis.Listener
var pubsubOnce sync.Once

// GetRedisPubSub returns singleton instance of pubsub listener
func GetRedisPubSub() redis.Listener {
	pubsubOnce.Do(func() {
		pubsub = redis.NewPubSub()
	})
	return pubsub
}

var queues redis.Listener
var queuesOnce sync.Once

// GetRedisQueues returns singleton instance of queues listener
func GetRedisQueues() redis.Listener {
	queuesOnce.Do(func() {
		queues = redis.NewQueues()
	})
	return queues
}

var clientPoolOnce sync.Once
var clientPool redis.ClientPoolInterface

func RedisClientPool() redis.ClientPoolInterface {
	clientPoolOnce.Do(func() {
		if clientPool != nil {
			return
		}

		clientPool = redis.NewClientPool()
	})

	return clientPool
}

func AddHMISessionToManyCache(vin string, uid int64) error {
	logger.Info().Msgf("Adding a unique connection to hmi:%s:many-sessions", vin)

	batch := redis.NewRedisBatchCommands()
	batch.Add("LPUSH", redis.HMIManySessionsKey(vin), uid)
	batch.Add("LLEN", redis.HMIManySessionsKey(vin))

	batchResponse, err := RedisClientPool().GetFromPool().ExecuteBatch(batch)
	if err != nil {
		errors.WithStack(err)
		return err
	}

	results, ok := batchResponse.([]int)
	if ok {
		if len(results) != 2 {
			return nil
		}
		total := results[1]
		if total > 1 {
			logger.Warn().Msgf("Currently storing %d connections in cache", total)
		}
	} else {
		logger.Debug().Msgf("Could not parse redis response when setting %s:%d", vin, uid)
	}
	return nil
}

func RemoveHMISessionFromManyCache(vin string, uid int64) error {
	logger.Info().Msgf("Removing a unique connection from hmi:%s:many-sessions", vin)
	_, err := RedisClientPool().GetFromPool().Execute("LREM", redis.HMIManySessionsKey(vin), 1, uid)
	if err != nil {
		logger.At(logger.Error(), vin, "conn").Err(err).Send()
	}
	return nil
}
