package metrics

import (
	"os"
	"runtime"
	"strconv"
	"time"

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

const (
	namespace = "rfs"
)

var (
	CommandDurationSeconds = prometheus.NewHistogramVec(
		prometheus.HistogramOpts{
			Namespace: namespace,
			Subsystem: "rfs",
			Name:      "command_duration_seconds",
			Help:      "Bucketed histogram of command duration seconds",
			Buckets:   prometheus.ExponentialBuckets(0.0001, 1.5, 40),
		}, []string{"type"})
	ReadWaitTimeDurationHistogram       = CommandDurationSeconds.WithLabelValues("read")
	ReadCacheWaitTimeDurationHistogram  = CommandDurationSeconds.WithLabelValues("read-cache")
	WriteWaitTimeDurationHistogram      = CommandDurationSeconds.WithLabelValues("write")
	WriteCacheWaitTimeDurationHistogram = CommandDurationSeconds.WithLabelValues("write-cache")
	FlushWaitTimeDurationHistogram      = CommandDurationSeconds.WithLabelValues("flush")
	FsyncWaitTimeDurationHistogram      = CommandDurationSeconds.WithLabelValues("fsync")
	OpenWaitTimeDurationHistogram       = CommandDurationSeconds.WithLabelValues("open")
	CommandSizeBytes                    = prometheus.NewHistogramVec(
		prometheus.HistogramOpts{
			Namespace: namespace,
			Subsystem: "rfs",
			Name:      "command_size_bytes",
			Help:      "Bucketed histogram of command size in bytes",
			Buckets:   prometheus.ExponentialBuckets(1, 2, 40),
		}, []string{"type"})
	WriteSizeByteHistogram      = CommandSizeBytes.WithLabelValues("write")
	WriteCacheSizeByteHistogram = CommandSizeBytes.WithLabelValues("write-cache")
	ReadSizeByteHistogram       = CommandSizeBytes.WithLabelValues("read")
	ReadCacheSizeByteHistogram  = CommandSizeBytes.WithLabelValues("read-cache")
	ThreadCPUSecondsTotal       = prometheus.NewCounterVec(
		prometheus.CounterOpts{
			Namespace: namespace,
			Subsystem: "thread",
			Name:      "cpu_seconds_total",
			Help:      "Total user and system CPU time spent in seconds by threads.",
		}, []string{"name", "pid"})
	CacheSizeBytes = prometheus.NewGaugeVec(
		prometheus.GaugeOpts{
			Namespace: namespace,
			Subsystem: "cache",
			Name:      "size_bytes",
			Help:      "The cache disk usage",
		}, []string{"type"})
	DiskCache = CacheSizeBytes.WithLabelValues("disk")
)

func init() {
	prometheus.MustRegister(CommandDurationSeconds)
	prometheus.MustRegister(CommandSizeBytes)
	prometheus.MustRegister(ThreadCPUSecondsTotal)
	prometheus.MustRegister(CacheSizeBytes)
	if runtime.GOOS == `linux` {
		go func() {
			var lastCPUTime float64
			pid := os.Getpid()
			rfsThreadCPUSecondsTotal := ThreadCPUSecondsTotal.WithLabelValues("rfs", strconv.FormatInt(int64(pid), 10))
			ticker := time.NewTicker(time.Second * 10)
			for range ticker.C {
				// CPU statistics are available only on Linux
				p, err := procfs.NewProc(pid)
				if err == nil {
					if stat, err := p.Stat(); err == nil {
						CPUTime := stat.CPUTime()
						rfsThreadCPUSecondsTotal.Add(CPUTime - lastCPUTime)
						lastCPUTime = CPUTime
					}
				}
			}
		}()
	}
}
