/*
 * 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"
	log "github.com/sirupsen/logrus"
	"math/rand"
	"sync"
	"time"

	"github.com/golang/protobuf/ptypes"
	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.SensorValueType_SENSOR_VALUE_TYPE_OTHER,
		Scale:     dmi.SensorValueScale_SENSOR_VALUE_SCALE_UNITS,
		Timestamp: ptypes.TimestampNow(),
	}
	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.SensorValueType_SENSOR_VALUE_TYPE_RPM,
		Scale:     dmi.SensorValueScale_SENSOR_VALUE_SCALE_UNITS,
		Timestamp: ptypes.TimestampNow(),
	}
	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.SensorValueType_SENSOR_VALUE_TYPE_OTHER,
		Scale:     dmi.SensorValueScale_SENSOR_VALUE_SCALE_GIGA,
		Timestamp: ptypes.TimestampNow(),
	}
	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.SensorValueType_SENSOR_VALUE_TYPE_OTHER,
		Scale:     dmi.SensorValueScale_SENSOR_VALUE_SCALE_GIGA,
		Timestamp: ptypes.TimestampNow(),
	}
	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.SensorValueType_SENSOR_VALUE_TYPE_CELSIUS,
		Scale:     dmi.SensorValueScale_SENSOR_VALUE_SCALE_UNITS,
		Timestamp: ptypes.TimestampNow(),
	}
	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()
}
