package redis

import (
	"sync"

	goredis "github.com/redis/go-redis/v9"
	"github.com/zeromicro/go-zero/core/stores/redis"
)

// PubSubClient returns a lazily constructed *go-redis Client used for
// Pub/Sub subscriptions. go-zero's wrapper does not expose Subscribe, so
// permission/notification modules that need Pub/Sub call this helper.
//
// The connection is independent from the go-zero connection pool because
// Subscribe holds the connection for the subscription lifetime; mixing
// them with the go-zero pool's command path would break the pool.
func (c *Client) PubSubClient() *goredis.Client {
	if c == nil || c.r == nil {
		return nil
	}
	c.psMu.Lock()
	defer c.psMu.Unlock()
	if c.ps != nil {
		return c.ps
	}
	addr := c.r.Addr
	user := c.r.User
	pass := c.r.Pass
	c.ps = goredis.NewClient(&goredis.Options{
		Addr:     addr,
		Username: user,
		Password: pass,
	})
	return c.ps
}

// ClosePubSub closes the lazy-loaded Pub/Sub client (if any). Safe to call
// even when never opened.
func (c *Client) ClosePubSub() error {
	if c == nil {
		return nil
	}
	c.psMu.Lock()
	defer c.psMu.Unlock()
	if c.ps == nil {
		return nil
	}
	err := c.ps.Close()
	c.ps = nil
	return err
}

// pubSubFields are the lazy state for PubSub. Lives here so client.go
// stays minimal; the struct is augmented via the embedded fields below.
type pubSubFields struct {
	psMu sync.Mutex
	ps   *goredis.Client
}

// reference to redis.Redis so the package compiles when only pubsub.go is
// edited. The actual struct definition is in client.go.
var _ = (*redis.Redis)(nil)
