#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2019 tribe29 GmbH - License: GNU General Public License v2
# This file is part of Checkmk (https://checkmk.com). It is subject to the terms and
# conditions defined in the file COPYING, which is part of this source code package.

# NOTE: Careful when replacing the *-import below with a more specific import. This can cause
# problems because it might remove variables from the check-context which are necessary for
# resolving legacy discovery results such as [("SUMMARY", "diskstat_default_levels")]. Furthermore,
# it might also remove variables needed for accessing discovery rulesets.
from cmk.base.check_legacy_includes.cpu_util import *  # pylint: disable=wildcard-import,unused-wildcard-import

# Note: This file is almost identical with ibm_svc_systemstats. We should
# create an include file for sharing common code!

# Example output from agent:
# <<<ibm_svc_systemstats:sep(58)>>>
# compression_cpu_pc:0:0:140325134929
# cpu_pc:2:2:140325134929
# fc_mb:640:1482:140325134754
# fc_io:46718:56258:140325134749
# sas_mb:0:0:140325134929
# sas_io:0:0:140325134929
# iscsi_mb:0:0:140325134929
# iscsi_io:0:0:140325134929
# write_cache_pc:0:1:140325134819
# total_cache_pc:70:75:140325134704
# vdisk_mb:207:533:140325134754
# vdisk_io:4827:5966:140325134819
# vdisk_ms:1:2:140325134759
# mdisk_mb:222:651:140325134754
# mdisk_io:4995:6741:140325134754
# mdisk_ms:1:3:140325134809
# drive_mb:0:0:140325134929
# drive_io:0:0:140325134929
# drive_ms:0:0:140325134929
# vdisk_r_mb:113:428:140325134524
# vdisk_r_io:2470:3672:140325134819
# vdisk_r_ms:1:4:140325134759
# vdisk_w_mb:93:143:140325134704
# vdisk_w_io:2359:3595:140325134859
# vdisk_w_ms:0:2:140325134704
# mdisk_r_mb:32:362:140325134754
# mdisk_r_io:1452:2825:140325134754
# mdisk_r_ms:4:7:140325134649
# mdisk_w_mb:189:291:140325134749
# mdisk_w_io:3542:4465:140325134714
# mdisk_w_ms:0:2:140325134819
# drive_r_mb:0:0:140325134929
# drive_r_io:0:0:140325134929
# drive_r_ms:0:0:140325134929
# drive_w_mb:0:0:140325134929
# drive_w_io:0:0:140325134929
# drive_w_ms:0:0:140325134929

# parses agent output into a structure like:
# {'Drives': {'r_mb': 0,   'w_mb': 0,   'r_io': 0,    'w_io': 0,    'r_ms': 0, 'w_ms': 0},
#  'MDisks': {'r_mb': 32,  'w_mb': 189, 'r_io': 1452, 'w_io': 3542, 'r_ms': 4, 'w_ms': 0},
#  'VDisks': {'r_mb': 113, 'w_mb': 93,  'r_io': 2470, 'w_io': 2359, 'r_ms': 1, 'w_ms': 0}}


def ibm_svc_systemstats_parse(info):
    parsed = {}
    for stat_name, stat_current, _stat_peak, _stat_peak_time in info:
        if stat_name in (
            "vdisk_r_mb",
            "vdisk_w_mb",
            "vdisk_r_io",
            "vdisk_w_io",
            "vdisk_r_ms",
            "vdisk_w_ms",
        ):
            if "VDisks" not in parsed:
                parsed["VDisks"] = {}
            stat_name = stat_name.replace("vdisk_", "")
            parsed["VDisks"][stat_name] = float(stat_current)
        if stat_name in (
            "mdisk_r_mb",
            "mdisk_w_mb",
            "mdisk_r_io",
            "mdisk_w_io",
            "mdisk_r_ms",
            "mdisk_w_ms",
        ):
            if "MDisks" not in parsed:
                parsed["MDisks"] = {}
            stat_name = stat_name.replace("mdisk_", "")
            parsed["MDisks"][stat_name] = float(stat_current)
        if stat_name in (
            "drive_r_mb",
            "drive_w_mb",
            "drive_r_io",
            "drive_w_io",
            "drive_r_ms",
            "drive_w_ms",
        ):
            if "Drives" not in parsed:
                parsed["Drives"] = {}
            stat_name = stat_name.replace("drive_", "")
            parsed["Drives"][stat_name] = float(stat_current)
    return parsed


#   .--disk IO-------------------------------------------------------------.
#   |                         _ _     _      ___ ___                       |
#   |                      __| (_)___| | __ |_ _/ _ \                      |
#   |                     / _` | / __| |/ /  | | | | |                     |
#   |                    | (_| | \__ \   <   | | |_| |                     |
#   |                     \__,_|_|___/_|\_\ |___\___/                      |
#   |                                                                      |
#   '----------------------------------------------------------------------'


def inventory_ibm_svc_systemstats_diskio(info):
    return [(key, None) for key in ibm_svc_systemstats_parse(info)]


def check_ibm_svc_systemstats_diskio(item, _no_params, info):
    parsed = ibm_svc_systemstats_parse(info)

    if item not in parsed:
        return 3, "%s not found in agent output" % item

    read_bytes = parsed[item]["r_mb"] * 1024 * 1024
    write_bytes = parsed[item]["w_mb"] * 1024 * 1024
    perfdata = [("read", read_bytes), ("write", write_bytes)]

    return (
        0,
        "%s/s read, %s/s write"
        % (get_bytes_human_readable(read_bytes), get_bytes_human_readable(write_bytes)),
        perfdata,
    )


check_info["ibm_svc_systemstats.diskio"] = {
    "check_function": check_ibm_svc_systemstats_diskio,
    "inventory_function": inventory_ibm_svc_systemstats_diskio,
    "service_description": "Throughput %s Total",
    "has_perfdata": True,
}

# .
#   .--iops----------------------------------------------------------------.
#   |                          _                                           |
#   |                         (_) ___  _ __  ___                           |
#   |                         | |/ _ \| '_ \/ __|                          |
#   |                         | | (_) | |_) \__ \                          |
#   |                         |_|\___/| .__/|___/                          |
#   |                                 |_|                                  |
#   '----------------------------------------------------------------------'


def inventory_ibm_svc_systemstats_iops(info):
    return [(key, None) for key in ibm_svc_systemstats_parse(info)]


def check_ibm_svc_systemstats_iops(item, _no_params, info):
    parsed = ibm_svc_systemstats_parse(info)

    if item not in parsed:
        return 3, "%s not found in agent output" % item

    read_iops = parsed[item]["r_io"]
    write_iops = parsed[item]["w_io"]
    perfdata = [("read", read_iops), ("write", write_iops)]

    return 0, "%s IO/s read, %s IO/s write" % (read_iops, write_iops), perfdata


check_info["ibm_svc_systemstats.iops"] = {
    "check_function": check_ibm_svc_systemstats_iops,
    "inventory_function": inventory_ibm_svc_systemstats_iops,
    "service_description": "IOPS %s Total",
    "has_perfdata": True,
}

# .
#   .--disk latency--------------------------------------------------------.
#   |             _ _     _      _       _                                 |
#   |          __| (_)___| | __ | | __ _| |_ ___ _ __   ___ _   _          |
#   |         / _` | / __| |/ / | |/ _` | __/ _ \ '_ \ / __| | | |         |
#   |        | (_| | \__ \   <  | | (_| | ||  __/ | | | (__| |_| |         |
#   |         \__,_|_|___/_|\_\ |_|\__,_|\__\___|_| |_|\___|\__, |         |
#   |                                                       |___/          |
#   '----------------------------------------------------------------------'


def inventory_ibm_svc_systemstats_disk_latency(info):
    return [(key, {}) for key in ibm_svc_systemstats_parse(info)]


def check_ibm_svc_systemstats_disk_latency(item, params, info):
    parsed = ibm_svc_systemstats_parse(info)

    if item not in parsed:
        yield 3, "%s not found in agent output" % item
        return

    if not params:
        params = {}  # Convert from previous None

    for what, latency in [("read", parsed[item]["r_ms"]), ("write", parsed[item]["w_ms"])]:

        yield check_levels(
            latency, what + "_latency", params.get(what), unit="ms", infoname="%s latency" % what
        )


check_info["ibm_svc_systemstats.disk_latency"] = {
    "check_function": check_ibm_svc_systemstats_disk_latency,
    "inventory_function": inventory_ibm_svc_systemstats_disk_latency,
    "service_description": "Latency %s Total",
    "has_perfdata": True,
    "group": "ibm_svc_total_latency",
}

# .
#   .--cpu-----------------------------------------------------------------.
#   |                                                                      |
#   |                           ___ _ __  _   _                            |
#   |                          / __| '_ \| | | |                           |
#   |                         | (__| |_) | |_| |                           |
#   |                          \___| .__/ \__,_|                           |
#   |                              |_|                                     |
#   |                                                                      |
#   '----------------------------------------------------------------------'

ibm_svc_cpu_default_levels = (90.0, 95.0)


def inventory_ibm_svc_systemstats_cpu(info):
    inventory = []
    for stat_name, _stat_current, _stat_peak, _stat_peak_time in info:
        if stat_name == "cpu_pc":
            inventory.append((None, "ibm_svc_cpu_default_levels"))
    return inventory


def check_ibm_svc_systemstats_cpu(item, params, info):
    for stat_name, stat_current, _stat_peak, _stat_peak_time in info:
        if stat_name == "cpu_pc":
            return check_cpu_util(int(stat_current), params)

    return 3, "value cpu_pc not found in agent output for node %s" % item


check_info["ibm_svc_systemstats.cpu_util"] = {
    "check_function": check_ibm_svc_systemstats_cpu,
    "inventory_function": inventory_ibm_svc_systemstats_cpu,
    "service_description": "CPU utilization Total",
    "has_perfdata": True,
    "group": "cpu_utilization",
}

# .
#   .--cache---------------------------------------------------------------.
#   |                                     _                                |
#   |                       ___ __ _  ___| |__   ___                       |
#   |                      / __/ _` |/ __| '_ \ / _ \                      |
#   |                     | (_| (_| | (__| | | |  __/                      |
#   |                      \___\__,_|\___|_| |_|\___|                      |
#   |                                                                      |
#   '----------------------------------------------------------------------'


def inventory_ibm_svc_systemstats_cache(info):
    inventory = []
    for stat_name, _stat_current, _stat_peak, _stat_peak_time in info:
        if stat_name == "total_cache_pc":
            inventory.append((None, None))
    return inventory


def check_ibm_svc_systemstats_cache(item, _no_params, info):
    write_cache_pc = None
    total_cache_pc = None

    for stat_name, stat_current, _stat_peak, _stat_peak_time in info:
        if stat_name == "total_cache_pc":
            total_cache_pc = int(stat_current)
        if stat_name == "write_cache_pc":
            write_cache_pc = int(stat_current)

    if total_cache_pc is None:
        return 3, "value total_cache_pc not found in agent output"
    if write_cache_pc is None:
        return 3, "value write_cache_pc not found in agent output"

    perfdata = [
        ("write_cache_pc", write_cache_pc, None, None, 0, 100),
        ("total_cache_pc", total_cache_pc, None, None, 0, 100),
    ]

    return (
        0,
        "Write cache usage is %d %%, total cache usage is %d %%" % (write_cache_pc, total_cache_pc),
        perfdata,
    )


check_info["ibm_svc_systemstats.cache"] = {
    "check_function": check_ibm_svc_systemstats_cache,
    "inventory_function": inventory_ibm_svc_systemstats_cache,
    "service_description": "Cache Total",
    "has_perfdata": True,
}
