// Package metrics 提供进程内的 Prometheus 指标注册中心与一组类型化的记录助手。
//
// 设计要点：
//   - 用私有 *prometheus.Registry（NOT prometheus.DefaultRegisterer），避免在
//     热重载 / 测试中重复注册默认注册表导致 panic。
//   - 通过 promhttp.HandlerFor(reg, ...) 暴露 Handler()；调用方（router）负责
//     鉴权门禁（/metrics 泄露成本/会话数，必须 admin/内网受限）。
//   - Record* 助手对外提供窄 API：其它模块只依赖这几个方法（或 acp 包内定义的
//     窄接口），无需 import prometheus。
//
// 指标清单（spec §11 §1205-1207）：
//   - acp_sessions_active            GaugeFunc   —— 当前活跃 ACP 会话数
//   - acp_session_exit_total{status} CounterVec  —— 会话退出计数（exited/crashed/…）
//   - acp_permission_decisions_total{outcome} CounterVec —— 权限决策计数
//     （auto/approved/denied/expired）
//   - jobs_dead_letter_total{type}   CounterVec  —— 死信任务计数（按 job type）
//   - llm_cost_usd_total             GaugeFunc   —— 累计 LLM 成本（USD）
package metrics

import (
	"net/http"

	"github.com/prometheus/client_golang/prometheus"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

// Metrics 持有私有注册表与各 collector。零值不可用，必须经 New 构造。
type Metrics struct {
	reg *prometheus.Registry

	sessionExits  *prometheus.CounterVec
	permDecisions *prometheus.CounterVec
	deadLetters   *prometheus.CounterVec
}

// New 构造 Metrics。activeSessions / llmCostTotal 是供 GaugeFunc 回调的取值
// 函数；二者可为 nil（nil 时对应 gauge 恒为 0），便于测试 / feature-off。
func New(activeSessions func() float64, llmCostTotal func() float64) *Metrics {
	reg := prometheus.NewRegistry()

	m := &Metrics{
		reg: reg,
		sessionExits: prometheus.NewCounterVec(prometheus.CounterOpts{
			Name: "acp_session_exit_total",
			Help: "Total number of ACP agent session exits, labeled by terminal status.",
		}, []string{"status"}),
		permDecisions: prometheus.NewCounterVec(prometheus.CounterOpts{
			Name: "acp_permission_decisions_total",
			Help: "Total number of ACP tool-permission decisions, labeled by outcome.",
		}, []string{"outcome"}),
		deadLetters: prometheus.NewCounterVec(prometheus.CounterOpts{
			Name: "jobs_dead_letter_total",
			Help: "Total number of jobs that exhausted retries and were dead-lettered, by job type.",
		}, []string{"type"}),
	}

	reg.MustRegister(m.sessionExits, m.permDecisions, m.deadLetters)

	if activeSessions == nil {
		activeSessions = func() float64 { return 0 }
	}
	if llmCostTotal == nil {
		llmCostTotal = func() float64 { return 0 }
	}
	reg.MustRegister(prometheus.NewGaugeFunc(prometheus.GaugeOpts{
		Name: "acp_sessions_active",
		Help: "Current number of active (starting/running) ACP agent sessions.",
	}, activeSessions))
	reg.MustRegister(prometheus.NewGaugeFunc(prometheus.GaugeOpts{
		Name: "llm_cost_usd_total",
		Help: "Cumulative LLM usage cost in USD across all endpoints.",
	}, llmCostTotal))

	return m
}

// Handler 返回 /metrics 的 http.Handler，绑定到本 Metrics 的私有注册表。
func (m *Metrics) Handler() http.Handler {
	return promhttp.HandlerFor(m.reg, promhttp.HandlerOpts{})
}

// Registry 暴露底层注册表，便于测试直接 Gather。
func (m *Metrics) Registry() *prometheus.Registry { return m.reg }

// RecordSessionExit 记录一次会话退出。status 取 acp.SessionStatus 字符串值
// （exited/crashed/…）。
func (m *Metrics) RecordSessionExit(status string) {
	if m == nil {
		return
	}
	m.sessionExits.WithLabelValues(status).Inc()
}

// RecordPermissionDecision 记录一次权限决策。outcome 取 auto/approved/denied/expired。
func (m *Metrics) RecordPermissionDecision(outcome string) {
	if m == nil {
		return
	}
	m.permDecisions.WithLabelValues(outcome).Inc()
}

// RecordDeadLetter 记录一次死信任务，按 job type 标签累加。
func (m *Metrics) RecordDeadLetter(jobType string) {
	if m == nil {
		return
	}
	m.deadLetters.WithLabelValues(jobType).Inc()
}
