/*
 * Copyright 2018-present Open Networking Foundation

 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at

 * http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package dmiserver

import (
	"context"
	"math/rand"
	"sync"
	"time"

	log "github.com/sirupsen/logrus"
	"google.golang.org/protobuf/types/known/timestamppb"

	dmi "github.com/opencord/device-management-interface/go/dmi"
)

//MetricGenerationFunc to generate the metrics to the kafka bus
type MetricGenerationFunc func(*dmi.Component, *DmiAPIServer) *dmi.Metric

// MetricTriggerConfig is the configuration of a metric and the time at which it will be exported
type MetricTriggerConfig struct {
	cfg dmi.MetricConfig
	t   time.Time
}

//DmiMetricsGenerator has the attributes for generating metrics
type DmiMetricsGenerator struct {
	apiSrv            *DmiAPIServer
	configuredMetrics map[dmi.MetricNames]MetricTriggerConfig
	access            sync.Mutex
	mgCancelFunc      context.CancelFunc
}

var dmiMG DmiMetricsGenerator

//StartMetricGenerator starts the metric generator
func StartMetricGenerator(apiSrv *DmiAPIServer) {
	log.Debugf("StartMetricGenerator invoked")
	// Seed the rand for use later on
	rand.Seed(time.Now().UnixNano())

	dmiMG = DmiMetricsGenerator{
		apiSrv: apiSrv,
	}
	dmiMG.configuredMetrics = make(map[dmi.MetricNames]MetricTriggerConfig)

	// Add CPU usage as a default Metric reported every 60 secs
	cpuMetricConfig := dmi.MetricConfig{
		MetricId:     dmi.MetricNames_METRIC_CPU_USAGE_PERCENTAGE,
		IsConfigured: true,
		PollInterval: 60,
	}
	dmiMG.configuredMetrics[dmi.MetricNames_METRIC_CPU_USAGE_PERCENTAGE] = MetricTriggerConfig{
		cfg: cpuMetricConfig,
		t:   time.Unix(0, 0),
	}

	// Add FAN speed metric as a default Metric reported every 120 secs
	fanSpeedMetricConfig := dmi.MetricConfig{
		MetricId:     dmi.MetricNames_METRIC_FAN_SPEED,
		IsConfigured: true,
		PollInterval: 120,
	}
	dmiMG.configuredMetrics[dmi.MetricNames_METRIC_FAN_SPEED] = MetricTriggerConfig{
		cfg: fanSpeedMetricConfig,
		t:   time.Unix(0, 0),
	}

	// Add RAM usage percentage metric reported every 60 seconds
	ramUsageMetricConfig := dmi.MetricConfig{
		MetricId:     dmi.MetricNames_METRIC_RAM_USAGE_PERCENTAGE,
		IsConfigured: false,
		PollInterval: 60,
	}
	dmiMG.configuredMetrics[dmi.MetricNames_METRIC_RAM_USAGE_PERCENTAGE] = MetricTriggerConfig{
		cfg: ramUsageMetricConfig,
		t:   time.Unix(0, 0),
	}

	// Add DISK usage percentage metric reported every 60 seconds
	diskUsageMetricConfig := dmi.MetricConfig{
		MetricId:     dmi.MetricNames_METRIC_DISK_USAGE_PERCENTAGE,
		IsConfigured: false,
		PollInterval: 60,
	}
	dmiMG.configuredMetrics[dmi.MetricNames_METRIC_DISK_USAGE_PERCENTAGE] = MetricTriggerConfig{
		cfg: diskUsageMetricConfig,
		t:   time.Unix(0, 0),
	}
	// Add Inner Surrounding TEMP usage percentage metric reported every 120 seconds
	innerTempUsageMetricConfig := dmi.MetricConfig{
		MetricId:     dmi.MetricNames_METRIC_INNER_SURROUNDING_TEMP,
		IsConfigured: true,
		PollInterval: 120,
	}
	dmiMG.configuredMetrics[dmi.MetricNames_METRIC_INNER_SURROUNDING_TEMP] = MetricTriggerConfig{
		cfg: innerTempUsageMetricConfig,
		t:   time.Unix(0, 0),
	}

	StartGeneratingMetrics()
}

// StartGeneratingMetrics starts the goroutine which submits metrics to the metrics channel
func StartGeneratingMetrics() {
	if dmiMG.apiSrv == nil {
		// Metric Generator is not yet initialized/started.
		// Means that the device is not managed on the DMI interface
		return
	}

	// initialize a new context
	var mgCtx context.Context
	mgCtx, dmiMG.mgCancelFunc = context.WithCancel(context.Background())

	go generateMetrics(mgCtx)
}

func generateMetrics(ctx context.Context) {
loop:
	for {
		select {
		case <-ctx.Done():
			log.Infof("Stopping generation of metrics ")
			break loop
		default:
			c := make(map[dmi.MetricNames]MetricTriggerConfig)

			dmiMG.access.Lock()
			for k, v := range dmiMG.configuredMetrics {
				c[k] = v
			}
			dmiMG.access.Unlock()

			now := time.Now()
			// For all the supported metrics
			for k, v := range c {
				if dmiMG.apiSrv.root == nil || dmiMG.apiSrv.root.Children == nil {
					// inventory might not yet be created or somehow disappeared
					break
				}

				if k == dmi.MetricNames_METRIC_CPU_USAGE_PERCENTAGE && v.cfg.IsConfigured {
					if now.Before(v.t) {
						continue
					}
					updateConfiguredMetrics(now, dmi.MetricNames_METRIC_CPU_USAGE_PERCENTAGE, &v)

					// Get the CPUs
					for _, cpu := range findComponentsOfType(dmiMG.apiSrv.root.Children, dmi.ComponentType_COMPONENT_TYPE_CPU) {
						m := generateCPUUsageMetric(cpu, dmiMG.apiSrv)
						logger.Debugf("Got metric %v", m)
						sendOutMetric(m, dmiMG.apiSrv)
					}
				} else if k == dmi.MetricNames_METRIC_FAN_SPEED && v.cfg.IsConfigured {
					if now.Before(v.t) {
						continue
					}
					updateConfiguredMetrics(now, dmi.MetricNames_METRIC_FAN_SPEED, &v)

					// Get the FANs
					for _, fan := range findComponentsOfType(dmiMG.apiSrv.root.Children, dmi.ComponentType_COMPONENT_TYPE_FAN) {
						m := generateFanSpeedMetric(fan, dmiMG.apiSrv)
						logger.Debugf("Got metric %v", m)
						sendOutMetric(m, dmiMG.apiSrv)
					}
				} else if k == dmi.MetricNames_METRIC_RAM_USAGE_PERCENTAGE && v.cfg.IsConfigured {
					if now.Before(v.t) {
						continue
					}
					updateConfiguredMetrics(now, dmi.MetricNames_METRIC_RAM_USAGE_PERCENTAGE, &v)
					// Get the RAM
					for _, ram := range findComponentsOfType(dmiMG.apiSrv.root.Children, dmi.ComponentType_COMPONENT_TYPE_MEMORY) {
						m := generateRAMUsageMetric(ram, dmiMG.apiSrv)
						logger.Debugf("Got metric for ram usage percentage %v", m)
						sendOutMetric(m, dmiMG.apiSrv)
					}
				} else if k == dmi.MetricNames_METRIC_DISK_USAGE_PERCENTAGE && v.cfg.IsConfigured {
					if now.Before(v.t) {
						continue
					}
					updateConfiguredMetrics(now, dmi.MetricNames_METRIC_DISK_USAGE_PERCENTAGE, &v)
					// Get the DISK
					for _, disk := range findComponentsOfType(dmiMG.apiSrv.root.Children, dmi.ComponentType_COMPONENT_TYPE_STORAGE) {
						m := generateDiskUsageMetric(disk, dmiMG.apiSrv)
						logger.Debugf("Got metric for disk usage percentage %v", m)
						sendOutMetric(m, dmiMG.apiSrv)
					}
				} else if k == dmi.MetricNames_METRIC_INNER_SURROUNDING_TEMP && v.cfg.IsConfigured {
					if now.Before(v.t) {
						continue
					}
					updateConfiguredMetrics(now, dmi.MetricNames_METRIC_INNER_SURROUNDING_TEMP, &v)
					// Get the INNER  SURROUNDING TEMPERATURE
					for _, isTemp := range findComponentsOfType(dmiMG.apiSrv.root.Children, dmi.ComponentType_COMPONENT_TYPE_SENSOR) {
						m := generateInnerSurroundingTempMetric(isTemp, dmiMG.apiSrv)
						logger.Debugf("Got metric for inner surrounding temperature %v", m)
						sendOutMetric(m, dmiMG.apiSrv)
					}
				}
			}
			time.Sleep(1 * time.Second)
		}
	}
}

func sendOutMetric(metric interface{}, apiSrv *DmiAPIServer) {
	select {
	case apiSrv.metricChannel <- metric:
	default:
		logger.Debugf("Channel not ready dropping Metric")
	}
}

func updateConfiguredMetrics(curr time.Time, typ dmi.MetricNames, old *MetricTriggerConfig) {
	dmiMG.access.Lock()
	dmiMG.configuredMetrics[typ] = MetricTriggerConfig{
		cfg: old.cfg,
		t:   curr.Add(time.Second * time.Duration(old.cfg.PollInterval)),
	}
	dmiMG.access.Unlock()
}

func updateMetricIDAndMetaData(id dmi.MetricNames, c *dmi.Component, apiSrv *DmiAPIServer, m *dmi.Metric) *dmi.Metric {
	m.MetricId = id
	m.MetricMetadata = &dmi.MetricMetaData{
		DeviceUuid: &dmi.Uuid{
			Uuid: apiSrv.uuid,
		},
		ComponentUuid: c.Uuid,
		ComponentName: c.Name,
	}
	return m
}

func generateCPUUsageMetric(cpu *dmi.Component, apiSrv *DmiAPIServer) *dmi.Metric {
	var met dmi.Metric
	met = *updateMetricIDAndMetaData(dmi.MetricNames_METRIC_CPU_USAGE_PERCENTAGE, cpu, apiSrv, &met)
	met.Value = &dmi.ComponentSensorData{
		Value:     generateRand(1, 20),
		Type:      dmi.DataValueType_VALUE_TYPE_OTHER,
		Scale:     dmi.ValueScale_VALUE_SCALE_UNITS,
		Timestamp: timestamppb.Now(),
	}
	return &met
}

func generateFanSpeedMetric(fan *dmi.Component, apiSrv *DmiAPIServer) *dmi.Metric {
	var met dmi.Metric
	met = *updateMetricIDAndMetaData(dmi.MetricNames_METRIC_FAN_SPEED, fan, apiSrv, &met)
	met.Value = &dmi.ComponentSensorData{
		Value:     generateRand(3000, 4000),
		Type:      dmi.DataValueType_VALUE_TYPE_RPM,
		Scale:     dmi.ValueScale_VALUE_SCALE_UNITS,
		Timestamp: timestamppb.Now(),
	}
	return &met
}

// return a random number RAND which is:  lValue < RAND < hValue
func generateRand(lValue, hValue int32) int32 {
	if lValue >= hValue {
		return 0
	}

	diff := hValue - lValue

	randVal := rand.Int31n(diff)

	return lValue + randVal
}

//UpdateMetricConfig Adds/Updates the passed metric configuration
func UpdateMetricConfig(newCfg *dmi.MetricConfig) {
	dmiMG.access.Lock()
	dmiMG.configuredMetrics[newCfg.GetMetricId()] = MetricTriggerConfig{
		cfg: *newCfg,
		t:   time.Unix(0, 0),
	}
	dmiMG.access.Unlock()
	logger.Infof("Metric updated %v", newCfg)
}

func generateRAMUsageMetric(ram *dmi.Component, apiSrv *DmiAPIServer) *dmi.Metric {
	var met dmi.Metric
	met = *updateMetricIDAndMetaData(dmi.MetricNames_METRIC_RAM_USAGE_PERCENTAGE, ram, apiSrv, &met)
	met.Value = &dmi.ComponentSensorData{
		Value:     generateRand(1, 8),
		Type:      dmi.DataValueType_VALUE_TYPE_OTHER,
		Scale:     dmi.ValueScale_VALUE_SCALE_GIGA,
		Timestamp: timestamppb.Now(),
	}
	return &met
}

func generateDiskUsageMetric(disk *dmi.Component, apiSrv *DmiAPIServer) *dmi.Metric {
	var met dmi.Metric
	met = *updateMetricIDAndMetaData(dmi.MetricNames_METRIC_DISK_USAGE_PERCENTAGE, disk, apiSrv, &met)
	met.Value = &dmi.ComponentSensorData{
		Value:     generateRand(50, 500),
		Type:      dmi.DataValueType_VALUE_TYPE_OTHER,
		Scale:     dmi.ValueScale_VALUE_SCALE_GIGA,
		Timestamp: timestamppb.Now(),
	}
	return &met
}

func generateInnerSurroundingTempMetric(istemp *dmi.Component, apiSrv *DmiAPIServer) *dmi.Metric {
	var met dmi.Metric
	met = *updateMetricIDAndMetaData(dmi.MetricNames_METRIC_INNER_SURROUNDING_TEMP, istemp, apiSrv, &met)
	met.Value = &dmi.ComponentSensorData{
		Value:     generateRand(30, 40),
		Type:      dmi.DataValueType_VALUE_TYPE_CELSIUS,
		Scale:     dmi.ValueScale_VALUE_SCALE_UNITS,
		Timestamp: timestamppb.Now(),
	}
	return &met
}

// get the metrics list
func getMetricsList() []*dmi.MetricConfig {
	components := make(map[dmi.MetricNames]MetricTriggerConfig)
	dmiMG.access.Lock()

	for key, value := range dmiMG.configuredMetrics {
		components[key] = value
	}

	dmiMG.access.Unlock()

	var toRet []*dmi.MetricConfig
	for _, v := range components {
		metricConfig := v.cfg
		toRet = append(toRet, &metricConfig)
	}
	logger.Debugf("Metrics list %+v", toRet)
	return toRet
}

func getMetric(comp *dmi.Component, metricID dmi.MetricNames) *dmi.Metric {
	switch metricID {
	case dmi.MetricNames_METRIC_FAN_SPEED:
		metric := generateFanSpeedMetric(comp, dmiMG.apiSrv)
		return metric

	case dmi.MetricNames_METRIC_CPU_USAGE_PERCENTAGE:
		metric := generateCPUUsageMetric(comp, dmiMG.apiSrv)
		return metric

	case dmi.MetricNames_METRIC_RAM_USAGE_PERCENTAGE:
		metric := generateRAMUsageMetric(comp, dmiMG.apiSrv)
		return metric

	case dmi.MetricNames_METRIC_DISK_USAGE_PERCENTAGE:
		metric := generateDiskUsageMetric(comp, dmiMG.apiSrv)
		return metric

	case dmi.MetricNames_METRIC_INNER_SURROUNDING_TEMP:
		metric := generateInnerSurroundingTempMetric(comp, dmiMG.apiSrv)
		return metric
	}
	return nil
}

// StopGeneratingMetrics stops the goroutine which submits metrics to the metrics channel
func StopGeneratingMetrics() {
	if dmiMG.mgCancelFunc != nil {
		dmiMG.mgCancelFunc()
	}
}

// StopMetricGenerator stops the generation of metrics and cleans up all local context
func StopMetricGenerator() {
	logger.Debugf("StopMetricGenerator invoked")

	StopGeneratingMetrics()

	dmiMG.access.Lock()
	// reset it to an empty map
	dmiMG.configuredMetrics = make(map[dmi.MetricNames]MetricTriggerConfig)
	dmiMG.access.Unlock()
}
