package containers

import (
	"github.com/coroot/coroot-node-agent/ebpftracer/l7"
	"github.com/prometheus/client_golang/prometheus"
)

var metrics = struct {
	ContainerInfo *prometheus.Desc
	Restarts      *prometheus.Desc

	CPULimit      *prometheus.Desc
	CPUUsage      *prometheus.Desc
	CPUDelay      *prometheus.Desc
	ThrottledTime *prometheus.Desc

	MemoryLimit *prometheus.Desc
	MemoryRss   *prometheus.Desc
	MemoryCache *prometheus.Desc
	OOMKills    *prometheus.Desc

	DiskDelay      *prometheus.Desc
	DiskSize       *prometheus.Desc
	DiskUsed       *prometheus.Desc
	DiskReserved   *prometheus.Desc
	DiskReadOps    *prometheus.Desc
	DiskReadBytes  *prometheus.Desc
	DiskWriteOps   *prometheus.Desc
	DiskWriteBytes *prometheus.Desc

	NetListenInfo            *prometheus.Desc
	NetConnectionsSuccessful *prometheus.Desc
	NetConnectionsTotalTime  *prometheus.Desc
	NetConnectionsFailed     *prometheus.Desc
	NetConnectionsActive     *prometheus.Desc
	NetRetransmits           *prometheus.Desc
	NetLatency               *prometheus.Desc
	NetBytesSent             *prometheus.Desc
	NetBytesReceived         *prometheus.Desc
	NetBytesSentPer          *prometheus.Desc
	NetBytesReceivedPer      *prometheus.Desc
	NetDataLatency           *prometheus.Desc
	NetDataDuration          *prometheus.Desc
	NetEstTime               *prometheus.Desc

	NetAcceptsSuccessful   *prometheus.Desc
	NetAcceptsActive       *prometheus.Desc
	NetAcceptBytesSent     *prometheus.Desc
	NetAcceptBytesReceived *prometheus.Desc

	LogMessages *prometheus.Desc

	ApplicationType *prometheus.Desc

	JvmInfo              *prometheus.Desc
	JvmHeapSize          *prometheus.Desc
	JvmHeapUsed          *prometheus.Desc
	JvmGCTime            *prometheus.Desc
	JvmSafepointTime     *prometheus.Desc
	JvmSafepointSyncTime *prometheus.Desc

	PythonThreadLockWaitTime *prometheus.Desc

	Ip2Fqdn *prometheus.Desc
}{
	ContainerInfo: metric("process_info", "Meta information about the process", "image", "systemd_triggered_by"),

	Restarts: metric("process_restarts_total", "Number of times the process was restarted"),

	CPULimit:      metric("process_resources_cpu_limit_cores", "CPU limit of the process"),
	CPUUsage:      metric("process_resources_cpu_usage_seconds_total", "Total CPU time consumed by the process"),
	CPUDelay:      metric("process_resources_cpu_delay_seconds_total", "Total time duration processes of the process have been waiting for a CPU (while being runnable)"),
	ThrottledTime: metric("process_resources_cpu_throttled_seconds_total", "Total time duration the process has been throttled"),

	MemoryLimit: metric("process_resources_memory_limit_bytes", "Memory limit of the process"),
	MemoryRss:   metric("process_resources_memory_rss_bytes", "Amount of physical memory used by the process (doesn't include page cache)"),
	MemoryCache: metric("process_resources_memory_cache_bytes", "Amount of page cache memory allocated by the process"),
	OOMKills:    metric("process_oom_kills_total", "Total number of times the process was terminated by the OOM killer"),

	DiskDelay:      metric("process_resources_disk_delay_seconds_total", "Total time duration processes of the process have been waiting fot I/Os to complete"),
	DiskSize:       metric("process_resources_disk_size_bytes", "Total capacity of the volume", "mount_point", "device", "volume"),
	DiskUsed:       metric("process_resources_disk_used_bytes", "Used capacity of the volume", "mount_point", "device", "volume"),
	DiskReserved:   metric("process_resources_disk_reserved_bytes", "Reserved capacity of the volume", "mount_point", "device", "volume"),
	DiskReadOps:    metric("process_resources_disk_reads_total", "Total number of reads completed successfully by the process", "mount_point", "device", "volume"),
	DiskReadBytes:  metric("process_resources_disk_read_bytes_total", "Total number of bytes read from the disk by the process", "mount_point", "device", "volume"),
	DiskWriteOps:   metric("process_resources_disk_writes_total", "Total number of writes completed successfully by the process", "mount_point", "device", "volume"),
	DiskWriteBytes: metric("process_resources_disk_written_bytes_total", "Total number of bytes written to the disk by the process", "mount_point", "device", "volume"),

	NetListenInfo:            metric("process_net_tcp_listen_info", "Listen address of the process", "listen_addr", "proxy"),
	NetConnectionsSuccessful: metric("process_net_tcp_successful_connects_total", "Total number of successful TCP connects", "instance_id", "app_id", "target_app_id", "app_name", "src", "destination", "actual_destination"),
	NetConnectionsTotalTime:  metric("process_net_tcp_connection_time_seconds_total", "Time spent on TCP connections", "instance_id", "app_id", "target_app_id", "app_name", "src", "destination", "actual_destination"),
	NetConnectionsFailed:     metric("process_net_tcp_failed_connects_total", "Total number of failed TCP connects", "instance_id", "app_id", "target_app_id", "app_name", "destination", "actual_destination"),
	NetConnectionsActive:     metric("process_net_tcp_active_connections", "Number of active outbound connections used by the process", "destination", "actual_destination"),
	NetRetransmits:           metric("process_net_tcp_retransmits_total", "Total number of retransmitted TCP segments", "instance_id", "app_id", "target_app_id", "app_name", "src", "destination", "actual_destination"),
	NetLatency:               metric("process_net_latency_seconds", "Round-trip time between the process and a remote IP", "destination_ip"),
	NetBytesSent:             metric("process_net_tcp_bytes_sent_total", "Total number of bytes sent to the peer", "instance_id", "app_id", "target_app_id", "app_name", "src", "destination", "actual_destination"),
	NetBytesReceived:         metric("process_net_tcp_bytes_received_total", "Total number of bytes received from the peer", "instance_id", "app_id", "target_app_id", "app_name", "src", "destination", "actual_destination"),
	NetBytesSentPer:          metric("process_net_tcp_bytes_sent_per", "Per number of bytes sent to the peer", "instance_id", "app_id", "target_app_id", "app_name", "src", "destination", "actual_destination"),
	NetBytesReceivedPer:      metric("process_net_tcp_bytes_received_per", "Per number of bytes received from the peer", "instance_id", "app_id", "target_app_id", "app_name", "src", "destination", "actual_destination"),
	NetAcceptsSuccessful:     metric("process_net_tcp_successful_accept_total", "Total number of successful TCP accepts", "destination", "actual_destination"),
	NetAcceptBytesSent:       metric("process_net_tcp_bytes_sent_accept_total", "Total number of bytes sent to the peer", "destination", "actual_destination"),
	NetAcceptBytesReceived:   metric("process_net_tcp_bytes_received_accept_total", "Total number of bytes received from the peer", "destination", "actual_destination"),
	NetDataLatency:           metric("process_net_tcp_data_latency_time", "Data latency", "instance_id", "app_id", "target_app_id", "app_name", "src", "destination", "actual_destination"),
	NetDataDuration:          metric("process_net_tcp_flow_duration_time", "Data duration", "instance_id", "app_id", "target_app_id", "app_name", "src", "destination", "actual_destination"),
	NetEstTime:               metric("process_net_tcp_connection_establish_time", "Established time", "instance_id", "app_id", "target_app_id", "app_name", "src", "destination", "actual_destination"),

	LogMessages: metric("process_log_messages_total", "Number of messages grouped by the automatically extracted repeated pattern", "source", "level", "pattern_hash", "sample"),

	ApplicationType: metric("process_application_type", "Type of the application running in the process (e.g. memcached, postgres, mysql)", "application_type"),

	JvmInfo:              metric("process_jvm_info", "Meta information about the JVM", "jvm", "java_version"),
	JvmHeapSize:          metric("process_jvm_heap_size_bytes", "Total heap size in bytes", "jvm"),
	JvmHeapUsed:          metric("process_jvm_heap_used_bytes", "Used heap size in bytes", "jvm"),
	JvmGCTime:            metric("process_jvm_gc_time_seconds", "Time spent in the given JVM garbage collector in seconds", "jvm", "gc"),
	JvmSafepointTime:     metric("process_jvm_safepoint_time_seconds", "Time the application has been stopped for safepoint operations in seconds", "jvm"),
	JvmSafepointSyncTime: metric("process_jvm_safepoint_sync_time_seconds", "Time spent getting to safepoints in seconds", "jvm"),

	Ip2Fqdn: metric("ip_to_fqdn", "Mapping IP addresses to FQDNs based on DNS requests initiated by processs", "ip", "fqdn"),

	PythonThreadLockWaitTime: metric("process_python_thread_lock_wait_time_seconds", "Time spent waiting acquiring GIL in seconds"),
}

var (
	L7Requests = map[l7.Protocol]prometheus.CounterOpts{
		l7.ProtocolHTTP:      {Name: "process_http_requests_total", Help: "Total number of outbound HTTP requests"},
		l7.ProtocolPostgres:  {Name: "process_postgres_queries_total", Help: "Total number of outbound Postgres queries"},
		l7.ProtocolRedis:     {Name: "process_redis_queries_total", Help: "Total number of outbound Redis queries"},
		l7.ProtocolMemcached: {Name: "process_memcached_queries_total", Help: "Total number of outbound Memcached queries"},
		l7.ProtocolMysql:     {Name: "process_mysql_queries_total", Help: "Total number of outbound Mysql queries"},
		l7.ProtocolTiDB:      {Name: "process_tidb_queries_total", Help: "Total number of outbound TiDB queries"},
		l7.ProtocolMongo:     {Name: "process_mongo_queries_total", Help: "Total number of outbound Mongo queries"},
		l7.ProtocolKafka:     {Name: "process_kafka_requests_total", Help: "Total number of outbound Kafka requests"},
		l7.ProtocolCassandra: {Name: "process_cassandra_queries_total", Help: "Total number of outbound Cassandra requests"},
		l7.ProtocolRabbitmq:  {Name: "process_rabbitmq_messages_total", Help: "Total number of Rabbitmq messages produced or consumed by the process"},
		l7.ProtocolNats:      {Name: "process_nats_messages_total", Help: "Total number of NATS messages produced or consumed by the process"},
		l7.ProtocolDubbo2:    {Name: "process_dubbo_requests_total", Help: "Total number of outbound DUBBO requests"},
		l7.ProtocolDNS:       {Name: "process_dns_requests_total", Help: "Total number of outbound DNS requests"},
		l7.ProtocolDM:        {Name: "process_dm_queries_total", Help: "Total number of outbound DaMeng requests"},
	}
	L7Latency = map[l7.Protocol]prometheus.HistogramOpts{
		l7.ProtocolHTTP:      {Name: "process_http_requests_duration_seconds_total", Help: "Histogram of the response time for each outbound HTTP request"},
		l7.ProtocolPostgres:  {Name: "process_postgres_queries_duration_seconds_total", Help: "Histogram of the execution time for each outbound Postgres query"},
		l7.ProtocolRedis:     {Name: "process_redis_queries_duration_seconds_total", Help: "Histogram of the execution time for each outbound Redis query"},
		l7.ProtocolMemcached: {Name: "process_memcached_queries_duration_seconds_total", Help: "Histogram of the execution time for each outbound Memcached query"},
		l7.ProtocolMysql:     {Name: "process_mysql_queries_duration_seconds_total", Help: "Histogram of the execution time for each outbound Mysql query"},
		l7.ProtocolTiDB:      {Name: "process_tidb_queries_duration_seconds_total", Help: "Histogram of the execution time for each outbound TiDB query"},
		l7.ProtocolMongo:     {Name: "process_mongo_queries_duration_seconds_total", Help: "Histogram of the execution time for each outbound Mongo query"},
		l7.ProtocolKafka:     {Name: "process_kafka_requests_duration_seconds_total", Help: "Histogram of the execution time for each outbound Kafka request"},
		l7.ProtocolCassandra: {Name: "process_cassandra_queries_duration_seconds_total", Help: "Histogram of the execution time for each outbound Cassandra request"},
		l7.ProtocolDubbo2:    {Name: "process_dubbo_requests_duration_seconds_total", Help: "Histogram of the response time for each outbound DUBBO request"},
		l7.ProtocolDNS:       {Name: "process_dns_requests_duration_seconds_total", Help: "Histogram of the response time for each outbound DNS request"},
		l7.ProtocolDM:        {Name: "process_dm_queries_duration_seconds_total", Help: "Histogram of the execution time for each outbound DaMeng query"},
	}
)

func metric(name, help string, labels ...string) *prometheus.Desc {
	return prometheus.NewDesc(name, help, labels, nil)
}

func newCounter(name, help string, constLabels prometheus.Labels) prometheus.Counter {
	return prometheus.NewCounter(prometheus.CounterOpts{Name: name, Help: help, ConstLabels: constLabels})
}

func newCounterVec(name, help string, constLabels prometheus.Labels, labelNames ...string) *prometheus.CounterVec {
	return prometheus.NewCounterVec(prometheus.CounterOpts{Name: name, Help: help, ConstLabels: constLabels}, labelNames)
}

func newGauge(name, help string, constLabels prometheus.Labels) prometheus.Gauge {
	return prometheus.NewGauge(prometheus.GaugeOpts{Name: name, Help: help, ConstLabels: constLabels})
}

func newGaugeVec(name, help string, constLabels prometheus.Labels, labelNames ...string) *prometheus.GaugeVec {
	return prometheus.NewGaugeVec(prometheus.GaugeOpts{Name: name, Help: help, ConstLabels: constLabels}, labelNames)
}
