package database

import (
	"cargo-erp-backend/internal/config"
	"context"
	"fmt"

	"github.com/redis/go-redis/v9"
	"go.uber.org/zap"
)

type RedisInterface interface {
	Connect()
	Get(key string) *redis.Client
	RegisterCallback()
}
type Redis struct {
	Config config.ConfigInterface
	Logger *zap.Logger
	DB     map[string]*redis.Client
}

func NewRedis(config config.ConfigInterface, logger *zap.Logger) RedisInterface {
	return &Redis{
		Config: config,
		Logger: logger,
	}
}
func (r *Redis) Connect() {
	redisConfig := r.Config.Get("redis")
	dbRedis := make(map[string]*redis.Client)
	if v, ok := redisConfig.(map[string]interface{}); ok {
		for kNode, vNode := range v {
			r.Logger.Info("Parse config " + kNode)
			if params, ok := vNode.(map[string]interface{}); ok {
				password := ""
				host := ""
				port := ""
				if val, ok := params["password"]; ok {
					password = fmt.Sprintf("%v", val)
				}
				if val, ok := params["host"]; ok {
					host = fmt.Sprintf("%v", val)
				}
				if val, ok := params["port"]; ok {
					port = fmt.Sprintf("%v", val)
				}
				url := fmt.Sprintf("redis://:%v@%v:%v", password, host, port)
				r.Logger.Info(fmt.Sprintf("Connecting to Redis %v", kNode))
				opts, err := redis.ParseURL(url)
				if err != nil {
					r.Logger.Error(fmt.Sprintf("unable to parse redis URL %v", err.Error()))
				} else {
					client := redis.NewClient(opts)

					if err := client.Ping(context.Background()).Err(); err != nil {
						r.Logger.Error(fmt.Sprintf("unable to connect to redis: %v", err.Error()))
					} else {
						dbRedis[kNode] = client
					}
				}
				r.Logger.Info("Connected")
			} else {
				r.Logger.Fatal("Parse paramater redis config error")
			}
		}
	} else {
		r.Logger.Fatal("Parse paramater redis config error")
	}
	r.DB = dbRedis
}

func (r *Redis) Close() {
	for k, v := range r.DB {
		r.Logger.Info(fmt.Sprintf("Close Connection %v", k))
		v.Close()
		r.Logger.Info("Close Connection Done")
	}
	r.DB = make(map[string]*redis.Client)
}
func (r *Redis) RegisterCallback() {
	r.Config.RegisterOnChangeCallback(r.Reconnecting)
}
func (r *Redis) Reconnecting() {
	r.Close()
	r.Connect()
}
func (r *Redis) Get(key string) *redis.Client {
	if v, ok := r.DB[key]; ok {
		return v
	}
	return nil
}
