# -*- coding: utf-8 -*-
# Description: sensors netdata python.d plugin
# Author: Pawel Krupa (paulfantom)
# SPDX-License-Identifier: GPL-3.0-or-later

from collections import defaultdict

from bases.FrameworkServices.SimpleService import SimpleService
from third_party import lm_sensors as sensors

ORDER = [
    'temperature',
    'fan',
    'voltage',
    'current',
    'power',
    'energy',
    'humidity',
]

# This is a prototype of chart definition which is used to dynamically create self.definitions
CHARTS = {
    'temperature': {
        'options': [None, 'Temperature', 'Celsius', 'temperature', 'sensors.temperature', 'line'],
        'lines': [
            [None, None, 'absolute', 1, 1000]
        ]
    },
    'voltage': {
        'options': [None, 'Voltage', 'Volts', 'voltage', 'sensors.voltage', 'line'],
        'lines': [
            [None, None, 'absolute', 1, 1000]
        ]
    },
    'current': {
        'options': [None, 'Current', 'Ampere', 'current', 'sensors.current', 'line'],
        'lines': [
            [None, None, 'absolute', 1, 1000]
        ]
    },
    'power': {
        'options': [None, 'Power', 'Watt', 'power', 'sensors.power', 'line'],
        'lines': [
            [None, None, 'absolute', 1, 1000]
        ]
    },
    'fan': {
        'options': [None, 'Fans speed', 'Rotations/min', 'fans', 'sensors.fan', 'line'],
        'lines': [
            [None, None, 'absolute', 1, 1000]
        ]
    },
    'energy': {
        'options': [None, 'Energy', 'Joule', 'energy', 'sensors.energy', 'line'],
        'lines': [
            [None, None, 'incremental', 1, 1000]
        ]
    },
    'humidity': {
        'options': [None, 'Humidity', 'Percent', 'humidity', 'sensors.humidity', 'line'],
        'lines': [
            [None, None, 'absolute', 1, 1000]
        ]
    }
}

LIMITS = {
    'temperature': [-127, 1000],
    'voltage': [-400, 400],
    'current': [-127, 127],
    'fan': [0, 65535]
}

TYPE_MAP = {
    0: 'voltage',
    1: 'fan',
    2: 'temperature',
    3: 'power',
    4: 'energy',
    5: 'current',
    6: 'humidity',
    # 7: 'max_main',
    # 16: 'vid',
    # 17: 'intrusion',
    # 18: 'max_other',
    # 24: 'beep_enable'
}


class Service(SimpleService):
    def __init__(self, configuration=None, name=None):
        SimpleService.__init__(self, configuration=configuration, name=name)
        self.order = list()
        self.definitions = dict()
        self.chips = configuration.get('chips')
        self.priority = 60000

    def get_data(self):
        seen, data = dict(), dict()
        try:
            for chip in sensors.ChipIterator():
                chip_name = sensors.chip_snprintf_name(chip)
                seen[chip_name] = defaultdict(list)

                for feat in sensors.FeatureIterator(chip):
                    if feat.type not in TYPE_MAP:
                        continue

                    feat_type = TYPE_MAP[feat.type]
                    feat_name = str(feat.name.decode())
                    feat_label = sensors.get_label(chip, feat)
                    feat_limits = LIMITS.get(feat_type)
                    sub_feat = next(sensors.SubFeatureIterator(chip, feat))  # current value

                    if not sub_feat:
                        continue

                    try:
                        v = sensors.get_value(chip, sub_feat.number)
                    except sensors.SensorsError:
                        continue

                    if v is None:
                        continue

                    seen[chip_name][feat_type].append((feat_name, feat_label))

                    if feat_limits and (v < feat_limits[0] or v > feat_limits[1]):
                        continue

                    data[chip_name + '_' + feat_name] = int(v * 1000)

        except sensors.SensorsError as error:
            self.error(error)
            return None

        self.update_sensors_charts(seen)

        return data or None

    def update_sensors_charts(self, seen):
        for chip_name, feat in seen.items():
            if self.chips and not any([chip_name.startswith(ex) for ex in self.chips]):
                continue

            for feat_type, sub_feat in feat.items():
                if feat_type not in ORDER or feat_type not in CHARTS:
                    continue

                chart_id = '{}_{}'.format(chip_name, feat_type)
                if chart_id in self.charts:
                    continue

                params = [chart_id] + list(CHARTS[feat_type]['options'])
                new_chart = self.charts.add_chart(params)
                new_chart.params['priority'] = self.get_chart_priority(feat_type)

                for name, label in sub_feat:
                    lines = list(CHARTS[feat_type]['lines'][0])
                    lines[0] = chip_name + '_' + name
                    lines[1] = label
                    new_chart.add_dimension(lines)

    def check(self):
        try:
            sensors.init()
        except sensors.SensorsError as error:
            self.error(error)
            return False

        self.priority = self.charts.priority

        return bool(self.get_data() and self.charts)

    def get_chart_priority(self, feat_type):
        for i, v in enumerate(ORDER):
            if v == feat_type:
                return self.priority + i
        return self.priority
