package config

// Config tunes the permission module. All fields are optional; Defaults()
// populates production-safe values.
type Config struct {
	// Casbin is the RBAC enforcer config; empty disables enforcement
	// entirely (Check() returns Allow=true to keep dev mode running).
	Casbin CasbinConfig `json:",optional"`

	// Cache TTLs for read-side caches.
	Cache CacheConfig `json:",optional"`

	// Reload tunes the policy reload Pub/Sub subscriber.
	Reload ReloadConfig `json:",optional"`
}

// CasbinConfig governs the Casbin enforcer.
//
// ModelPath points at etc/rbac.conf (RBAC with domains + keyMatch2 +
// regexMatch). PolicyAdapter selects redis (default, Pub/Sub friendly) or
// mongo (read-from-collection on every load).
type CasbinConfig struct {
	Enabled       bool   `json:",optional"`
	ModelPath     string `json:",optional"`
	PolicyAdapter string `json:",optional,options=redis|mongo|auto"`
}

// CacheConfig tunes role / permission read caches stored in Redis.
type CacheConfig struct {
	UserRolesTTLSeconds int `json:",optional"`
	RolePermsTTLSeconds int `json:",optional"`
	CatalogTTLSeconds   int `json:",optional"`
}

// ReloadConfig configures Pub/Sub subscribers used to broadcast policy
// changes across pods.
type ReloadConfig struct {
	Channel              string `json:",optional"`
	DebounceMilliseconds int    `json:",optional"`
	HeartbeatSeconds     int    `json:",optional"`
}

// Defaults returns zero-value-safe defaults.
func (c Config) Defaults() Config {
	if c.Casbin.ModelPath == "" {
		c.Casbin.ModelPath = "etc/rbac.conf"
	}
	if c.Casbin.PolicyAdapter == "" {
		c.Casbin.PolicyAdapter = "auto"
	}
	if c.Cache.UserRolesTTLSeconds <= 0 {
		c.Cache.UserRolesTTLSeconds = 300
	}
	if c.Cache.RolePermsTTLSeconds <= 0 {
		c.Cache.RolePermsTTLSeconds = 300
	}
	if c.Cache.CatalogTTLSeconds <= 0 {
		c.Cache.CatalogTTLSeconds = 600
	}
	if c.Reload.Channel == "" {
		c.Reload.Channel = "casbin:reload"
	}
	if c.Reload.DebounceMilliseconds <= 0 {
		c.Reload.DebounceMilliseconds = 200
	}
	if c.Reload.HeartbeatSeconds <= 0 {
		c.Reload.HeartbeatSeconds = 60
	}
	return c
}

// Enabled reports whether the Casbin enforcer should be wired in.
func (c Config) Enabled() bool {
	return c.Casbin.Enabled
}
