// Package cache provides optional Redis cache support.
package cache

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"time"

	"git.kirsle.net/apps/gophertype/pkg/settings"
	redis "github.com/go-redis/redis/v8"
)

// Global Redis configuration.
var (
	RedisHost = "localhost"
	RedisPort = 6379
	RedisDB   = 0

	RedisClient *redis.Client
	ready       bool
)

// Error codes
var (
	ErrNotReady = errors.New("RedisClient not ready")
)

// Connect to Redis after loading the details from the site's settings.json.
func Connect() error {
	set := settings.Current
	if set.RedisEnabled {
		RedisClient = redis.NewClient(&redis.Options{
			Addr: fmt.Sprintf("%s:%d", set.RedisHost, set.RedisPort),
			DB:   set.RedisDB,
		})
		return nil
	}
	return errors.New("Redis not enabled in .settings.json")
}

// SetEx sets a cache key with expiration.
func SetEx(key string, value string, exp int64) error {
	if RedisClient == nil {
		return ErrNotReady
	}

	err := RedisClient.Set(context.Background(), key, value, time.Duration(exp)*time.Second).Err()
	return err
}

// Get a cache key.
func Get(key string) (string, error) {
	if RedisClient == nil {
		return "", ErrNotReady
	}

	val, err := RedisClient.Get(context.Background(), key).Result()
	return val, err
}

// GetJSON gets a JSON serialized value out of Redis.
func GetJSON(key string, v any) error {
	if val, err := Get(key); err != nil {
		return err
	} else {
		return json.Unmarshal([]byte(val), v)
	}
}

// Set sets a JSON serializable object in Redis.
func SetJSON(key string, v interface{}, expire time.Duration) error {
	bin, err := json.Marshal(v)
	if err != nil {
		return err
	}

	_, err = RedisClient.Set(context.Background(), key, bin, expire).Result()
	if err != nil {
		return err
	}

	return nil
}

// Delete a key from Redis.
func Delete(key string) error {
	return RedisClient.Del(context.Background(), key).Err()
}
