package config

import "time"

// The two blocks that shape what reaches him unasked: how nudges are batched,
// and whether a routine Maven inferred by herself may be announced at all.

// DigestConfig — notification batching / digest mode. When enabled, eligible
// nudges (severity ≤ SeverityCeiling) are queued in memory instead of sent
// immediately. Every Window duration (or when MaxItems reached), the queue is
// flushed as a single digest notification. nil ⇒ digest disabled (legacy
// behaviour — every nudge is sent as it fires).
type DigestConfig struct {
	Enabled         bool     `json:"enabled,omitempty"`
	Window          Duration `json:"window,omitempty"`           // e.g. "30m"
	MaxItems        int      `json:"max_items,omitempty"`        // flush at this count
	SeverityCeiling int      `json:"severity_ceiling,omitempty"` // max sev batched
}

// Digest defaults, applied in normaliseDigest.
const (
	DefaultDigestWindow          = 30 * time.Minute
	DefaultDigestMaxItems        = 5
	DefaultDigestSeverityCeiling = 2
)

// normaliseDigest is the one block that does NOT fold an absent block to nil:
// it materialises a disabled one instead, because the dispatcher reads
// c.Digest.Enabled without a nil check.
func (c *Config) normaliseDigest() {
	if c.Digest == nil {
		c.Digest = &DigestConfig{Enabled: false}
	}
	if c.Digest.Window == 0 {
		c.Digest.Window = Duration(DefaultDigestWindow)
	}
	if c.Digest.MaxItems == 0 {
		c.Digest.MaxItems = DefaultDigestMaxItems
	}
	if c.Digest.SeverityCeiling == 0 {
		c.Digest.SeverityCeiling = DefaultDigestSeverityCeiling
	}
}

// PatternProposalConfig — announcement policy for routines the digestion tick
// inferred by itself (Vikunja #247, #43).
//
// Detection is always on and always silent by default: the tick writes a
// proposed_routines row and the /routines page shows it. Notify is what turns
// "she noticed" into "she said something", and it is OFF unless configured —
// Maven is not a nag and not autonomous, so a behaviour that speaks without
// being asked has to be switched on deliberately, like weather and telegram.
//
// When Notify is on, the announcement is still heavily restrained:
//   - at most one proposal per tick, however many were detected;
//   - at most one per Cooldown across all pairs (not per pair), so a batch of
//     freshly-detected patterns cannot turn into a queue of interruptions;
//   - through the ordinary care-class gate (quiet hours / away / snooze), at
//     sev1 — the lowest severity there is. A proposal is the least urgent
//     thing Maven can say.
//
// A pair is only ever announced once, because it is only ever proposed once:
// proposed_routines is UNIQUE(action, object) and the row survives dismissal.
type PatternProposalConfig struct {
	// Notify — announce newly inferred routines. Default false.
	Notify bool `json:"notify,omitempty"`

	// Cooldown — minimum spacing between two proposal announcements. 0 ⇒
	// DefaultProposalCooldown (24h).
	Cooldown Duration `json:"cooldown,omitempty"`
}

// DefaultProposalCooldown — one inferred-routine announcement per day at
// most. A proposal is never urgent; if two patterns surface in the same
// hour, the second one waits, and the /routines page has it either way.
const DefaultProposalCooldown = 24 * time.Hour

// AnnounceProposals reports whether inferred routines may be announced. Safe
// on a nil receiver — an absent config block means silent detection.
func (p *PatternProposalConfig) AnnounceProposals() bool {
	return p != nil && p.Notify
}

// normalisePatternProposals leaves an absent block nil, which means silent
// detection. A present-but-partial one gets the cooldown, so `{"notify": true}`
// is enough to switch announcements on.
func (c *Config) normalisePatternProposals() {
	if c.PatternProposals != nil && c.PatternProposals.Cooldown <= 0 {
		c.PatternProposals.Cooldown = Duration(DefaultProposalCooldown)
	}
}
