package config

import "time"

// Two loops that run behind the conversation and never speak. Both are absent
// by default, and both follow the same rule as every other cost the owner did
// not ask for: present-but-empty (`{}`) is a valid "on with the defaults".

// MemoryEvalConfig — the background memory-evaluation loop (Vikunja #248).
// Absent ⇒ off, like every other capability that costs something the owner did
// not ask for. Each evaluation is a full LLM round-trip on the one resident
// model, which is the same model answering him; running it hourly by default
// would put a multi-second stall in front of an occasional voice turn for a
// feature he may not want.
//
// The loop only ever writes notes (source infer:memory-eval, visible on
// /dash). It cannot speak — see internal/memeval.
type MemoryEvalConfig struct {
	// Interval — how often to evaluate. 0 ⇒ DefaultMemoryEvalInterval.
	Interval Duration `json:"interval,omitempty"`

	// MaxItems — recent facts / notes / nudges fed into one evaluation.
	// 0 ⇒ memeval.DefaultMaxItems.
	MaxItems int `json:"max_items,omitempty"`

	// MinConfidence — observations the model scores below this are dropped.
	// 0 ⇒ memeval.DefaultMinConfidence.
	MinConfidence float64 `json:"min_confidence,omitempty"`
}

// DefaultMemoryEvalInterval — the plan's cadence (1h) for the memory
// evaluation loop, applied only when the block is present at all.
const DefaultMemoryEvalInterval = time.Hour

// normaliseMemoryEval leaves an absent block nil (⇒ no evaluation loop) and
// gives a present one the plan's cadence.
func (c *Config) normaliseMemoryEval() {
	if c.MemoryEval != nil && c.MemoryEval.Interval <= 0 {
		c.MemoryEval.Interval = Duration(DefaultMemoryEvalInterval)
	}
}

// EmailConfig — core's half of the email reader: how many task candidates one
// message may produce, and how long the extraction call may take.
//
// There is deliberately nothing about a mailbox here. Core does not connect to
// IMAP, does not know an account exists, and holds no mail credential — the
// reader daemon does, the same split mavpoll uses for the zenmoney token. This
// block only says "extraction is allowed, with these bounds".
type EmailConfig struct {
	// MaxTasks — candidates per message. 0 ⇒ email.MaxCandidates (3).
	MaxTasks int `json:"max_tasks,omitempty"`

	// Timeout — per-message extraction budget. 0 ⇒ DefaultEmailTimeout. This is
	// a Thinking model reading a mail; nobody is waiting on the answer, but a
	// hung llama-server must not pin the reader's connection forever.
	Timeout Duration `json:"timeout,omitempty"`
}

// DefaultEmailTimeout — extraction budget per message.
const DefaultEmailTimeout = 2 * time.Minute

// normaliseEmail leaves an absent block nil (⇒ mail ingestion refused) and
// gives a present one the timeout default.
func (c *Config) normaliseEmail() {
	if c.Email != nil && c.Email.Timeout <= 0 {
		c.Email.Timeout = Duration(DefaultEmailTimeout)
	}
}
