package rules

// RuleAware defines the interface for entities that can use rules
type RuleAware interface {
	// GetRuleManager returns the rule manager instance
	GetRuleManager() *RuleManager

	// GetZoneID returns the zone ID for zone-specific rules (0 for global)
	GetZoneID() int32
}

// RuleProvider defines the interface for providing rule access
type RuleProvider interface {
	// GetRule gets a rule by category and type, with optional zone override
	GetRule(category RuleCategory, ruleType RuleType, zoneID int32) *Rule

	// GetRuleByName gets a rule by category and type names, with optional zone override
	GetRuleByName(categoryName string, typeName string, zoneID int32) *Rule

	// GetGlobalRule gets a rule from the global rule set
	GetGlobalRule(category RuleCategory, ruleType RuleType) *Rule

	// GetZoneRule gets a zone-specific rule, falling back to global
	GetZoneRule(zoneID int32, category RuleCategory, ruleType RuleType) *Rule
}

// DatabaseInterface defines the interface for rule database operations
type DatabaseInterface interface {
	// LoadRuleSets loads all rule sets from database
	LoadRuleSets(ruleManager *RuleManager, reload bool) error

	// LoadGlobalRuleSet loads the global rule set
	LoadGlobalRuleSet(ruleManager *RuleManager) error

	// SaveRuleSet saves a rule set to database
	SaveRuleSet(ruleSet *RuleSet) error

	// DeleteRuleSet deletes a rule set from database
	DeleteRuleSet(ruleSetID int32) error

	// SetDefaultRuleSet sets the default rule set
	SetDefaultRuleSet(ruleSetID int32) error

	// GetDefaultRuleSetID gets the default rule set ID
	GetDefaultRuleSetID() (int32, error)

	// GetRuleSetList gets all rule sets
	GetRuleSetList() ([]RuleSetInfo, error)

	// ValidateDatabase validates required tables exist
	ValidateDatabase() error

	// CreateRulesTables creates the necessary database tables
	CreateRulesTables() error
}

// ConfigurationProvider defines the interface for configuration-based rule access
type ConfigurationProvider interface {
	// GetConfigValue gets a configuration value by key
	GetConfigValue(key string) (string, bool)

	// SetConfigValue sets a configuration value
	SetConfigValue(key string, value string) error

	// GetConfigValueInt gets a configuration value as integer
	GetConfigValueInt(key string, defaultValue int32) int32

	// GetConfigValueFloat gets a configuration value as float
	GetConfigValueFloat(key string, defaultValue float64) float64

	// GetConfigValueBool gets a configuration value as boolean
	GetConfigValueBool(key string, defaultValue bool) bool
}

// RuleValidator defines the interface for rule validation
type RuleValidator interface {
	// ValidateRule validates a rule's value
	ValidateRule(category RuleCategory, ruleType RuleType, value string) error

	// ValidateRuleSet validates an entire rule set
	ValidateRuleSet(ruleSet *RuleSet) []error

	// GetValidationRules gets validation rules for a category
	GetValidationRules(category RuleCategory) map[RuleType]ValidationRule
}

// ValidationRule defines validation criteria for a rule
type ValidationRule struct {
	Required    bool        // Whether the rule is required
	MinValue    interface{} // Minimum allowed value (for numeric types)
	MaxValue    interface{} // Maximum allowed value (for numeric types)
	ValidValues []string    // List of valid string values
	Pattern     string      // Regex pattern for validation
	Description string      // Description of the rule
}

// RuleEventHandler defines the interface for rule change events
type RuleEventHandler interface {
	// OnRuleChanged is called when a rule value changes
	OnRuleChanged(category RuleCategory, ruleType RuleType, oldValue string, newValue string)

	// OnRuleSetChanged is called when a rule set is modified
	OnRuleSetChanged(ruleSetID int32, action string)

	// OnGlobalRuleSetChanged is called when the global rule set changes
	OnGlobalRuleSetChanged(oldRuleSetID int32, newRuleSetID int32)
}

// RuleCache defines the interface for rule caching
type RuleCache interface {
	// GetCachedRule gets a cached rule
	GetCachedRule(key string) (*Rule, bool)

	// CacheRule caches a rule
	CacheRule(key string, rule *Rule, ttl int64)

	// InvalidateCache invalidates cached rules
	InvalidateCache(pattern string)

	// ClearCache clears all cached rules
	ClearCache()

	// GetCacheStats gets cache statistics
	GetCacheStats() CacheStats
}

// CacheStats contains cache performance statistics
type CacheStats struct {
	Hits        int64   // Number of cache hits
	Misses      int64   // Number of cache misses
	Entries     int64   // Number of cached entries
	Memory      int64   // Memory usage in bytes
	HitRatio    float64 // Cache hit ratio
	LastCleared int64   // Timestamp of last cache clear
}

// RuleManagerAdapter provides a simplified interface to the rule manager
type RuleManagerAdapter struct {
	ruleManager *RuleManager
	zoneID      int32
}

// NewRuleManagerAdapter creates a new rule manager adapter
func NewRuleManagerAdapter(ruleManager *RuleManager, zoneID int32) *RuleManagerAdapter {
	return &RuleManagerAdapter{
		ruleManager: ruleManager,
		zoneID:      zoneID,
	}
}

// GetRule gets a rule using the adapter's zone ID
func (rma *RuleManagerAdapter) GetRule(category RuleCategory, ruleType RuleType) *Rule {
	if rma.zoneID != 0 {
		return rma.ruleManager.GetZoneRule(rma.zoneID, category, ruleType)
	}
	return rma.ruleManager.GetGlobalRule(category, ruleType)
}

// GetRuleByName gets a rule by name using the adapter's zone ID
func (rma *RuleManagerAdapter) GetRuleByName(categoryName string, typeName string) *Rule {
	rule := rma.ruleManager.GetGlobalRuleByName(categoryName, typeName)

	// If we have a zone ID, check for zone-specific override
	if rma.zoneID != 0 && rule != nil {
		zoneRule := rma.ruleManager.GetZoneRule(rma.zoneID, rule.GetCategory(), rule.GetType())
		if zoneRule != nil {
			return zoneRule
		}
	}

	return rule
}

// GetInt32 gets a rule value as int32
func (rma *RuleManagerAdapter) GetInt32(category RuleCategory, ruleType RuleType) int32 {
	rule := rma.GetRule(category, ruleType)
	if rule != nil {
		return rule.GetInt32()
	}
	return 0
}

// GetFloat64 gets a rule value as float64
func (rma *RuleManagerAdapter) GetFloat64(category RuleCategory, ruleType RuleType) float64 {
	rule := rma.GetRule(category, ruleType)
	if rule != nil {
		return rule.GetFloat64()
	}
	return 0.0
}

// GetBool gets a rule value as bool
func (rma *RuleManagerAdapter) GetBool(category RuleCategory, ruleType RuleType) bool {
	rule := rma.GetRule(category, ruleType)
	if rule != nil {
		return rule.GetBool()
	}
	return false
}

// GetString gets a rule value as string
func (rma *RuleManagerAdapter) GetString(category RuleCategory, ruleType RuleType) string {
	rule := rma.GetRule(category, ruleType)
	if rule != nil {
		return rule.GetString()
	}
	return ""
}

// SetZoneID sets the zone ID for the adapter
func (rma *RuleManagerAdapter) SetZoneID(zoneID int32) {
	rma.zoneID = zoneID
}

// GetZoneID gets the current zone ID
func (rma *RuleManagerAdapter) GetZoneID() int32 {
	return rma.zoneID
}

// RuleServiceConfig contains configuration for rule services
type RuleServiceConfig struct {
	DatabaseEnabled bool               // Whether to use database storage
	CacheEnabled    bool               // Whether to enable rule caching
	CacheTTL        int64              // Cache TTL in seconds
	MaxCacheSize    int64              // Maximum cache size in bytes
	EventHandlers   []RuleEventHandler // Event handlers to register
	Validators      []RuleValidator    // Validators to register
}

// RuleService provides high-level rule management functionality
type RuleService struct {
	ruleManager   *RuleManager
	database      DatabaseInterface
	cache         RuleCache
	eventHandlers []RuleEventHandler
	validators    []RuleValidator
	config        RuleServiceConfig
}

// NewRuleService creates a new rule service
func NewRuleService(config RuleServiceConfig) *RuleService {
	return &RuleService{
		ruleManager:   NewRuleManager(),
		eventHandlers: config.EventHandlers,
		validators:    config.Validators,
		config:        config,
	}
}

// Initialize initializes the rule service
func (rs *RuleService) Initialize() error {
	// Load rules from database if enabled
	if rs.config.DatabaseEnabled && rs.database != nil {
		err := rs.database.LoadRuleSets(rs.ruleManager, false)
		if err != nil {
			return err
		}
	}

	return nil
}

// GetRuleManager returns the underlying rule manager
func (rs *RuleService) GetRuleManager() *RuleManager {
	return rs.ruleManager
}

// GetAdapter returns a rule manager adapter for a specific zone
func (rs *RuleService) GetAdapter(zoneID int32) *RuleManagerAdapter {
	return NewRuleManagerAdapter(rs.ruleManager, zoneID)
}

// SetDatabase sets the database service
func (rs *RuleService) SetDatabase(db DatabaseInterface) {
	rs.database = db
}

// SetCache sets the cache service
func (rs *RuleService) SetCache(cache RuleCache) {
	rs.cache = cache
}

// AddEventHandler adds an event handler
func (rs *RuleService) AddEventHandler(handler RuleEventHandler) {
	rs.eventHandlers = append(rs.eventHandlers, handler)
}

// AddValidator adds a validator
func (rs *RuleService) AddValidator(validator RuleValidator) {
	rs.validators = append(rs.validators, validator)
}

// Shutdown shuts down the rule service
func (rs *RuleService) Shutdown() error {
	// Clear cache if enabled
	if rs.cache != nil {
		rs.cache.ClearCache()
	}

	return nil
}
