// Package rules is the Phase 6 notification rules engine. Rules live in
// `config/notification-rules.yaml` (operator source of truth) and are
// mirrored into the `notification_rules` SQLite table on load + reload.
//
// The engine subscribes to bus topics for event-driven triggers
// (filter_grab, torrent_completed, tracker_scrape_error) and runs a
// periodic tick for threshold-style triggers (ratio_threshold,
// custom_query). Per-rule cooldowns are stored in last_fired_at.
package rules

import (
	"context"

	"github.com/operator/command-center/internal/notifications"
)

// Rule is the runtime shape, loaded from notification-rules.yaml.
type Rule struct {
	Name            string                       `yaml:"name"`
	Enabled         *bool                        `yaml:"enabled,omitempty"`
	Trigger         TriggerConfig                `yaml:"trigger"`
	Channels        []string                     `yaml:"channels"`
	CooldownSeconds int                          `yaml:"cooldown_seconds"`
	ChannelConfig   map[string]map[string]any    `yaml:"channel_config,omitempty"`
}

// IsEnabled defaults to false (operator must opt in) per Appendix D.
func (r Rule) IsEnabled() bool {
	if r.Enabled == nil {
		return false
	}
	return *r.Enabled
}

// TriggerConfig is the per-trigger settings blob. `type` picks the
// implementation; the rest is interpreted by that implementation.
type TriggerConfig struct {
	Type   string         `yaml:",inline"-"`
	Config map[string]any `yaml:",inline"`
}

// Document is the on-disk shape of notification-rules.yaml.
type Document struct {
	Rules []Rule `yaml:"rules"`
}

// Trigger is the contract every trigger type implements. A trigger may be
// event-driven (Subscribe) OR periodic (Evaluate); the engine wires up
// whichever the implementation supports.
type Trigger interface {
	// Type returns the YAML `trigger.type` string this implementation handles.
	Type() string

	// EventTopics returns the eventbus topics this trigger reacts to. Empty
	// slice means the trigger is purely periodic.
	EventTopics() []string

	// MatchEvent inspects a bus event and returns a Notification (and true)
	// if the event matches the rule's configuration. Called once per bus
	// event for each rule of this trigger type.
	MatchEvent(ctx context.Context, cfg map[string]any, topic string, payload any) (notifications.Notification, bool)

	// PeriodicEvaluate runs on the engine's tick (default 60s). Returns
	// zero or more notifications. Empty implementations fall back to a
	// nil return; the engine treats nil and empty equivalently.
	PeriodicEvaluate(ctx context.Context, cfg map[string]any) ([]notifications.Notification, error)
}
