#!/usr/bin/env python3
# -*- coding: utf-8; py-indent-offset: 4 -*-
#
# Author:  Linuxfabrik GmbH, Zurich, Switzerland
# Contact: info (at) linuxfabrik (dot) ch
#          https://www.linuxfabrik.ch/
# License: The Unlicense, see LICENSE file.

# https://github.com/Linuxfabrik/monitoring-plugins/blob/main/CONTRIBUTING.md

"""See the check's README for more details."""

import argparse
import json
import sys

import lib.args
import lib.base
import lib.huawei
import lib.human
import lib.lftest
import lib.time
import lib.txt
from lib.globals import STATE_CRIT, STATE_OK, STATE_UNKNOWN, STATE_WARN

__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
__version__ = '2026040801'

DESCRIPTION = """Checks the health and running status of all HyperMetro pairs on a Huawei OceanStor
Dorado storage system via the REST API (/hypermetropair endpoint). Alerts when any
pair reports a non-normal state or synchronization issue."""

DEFAULT_CACHE_EXPIRE = 15  # minutes; default session timeout period is 20 minutes
DEFAULT_INSECURE = True
DEFAULT_NO_PROXY = False
DEFAULT_SCOPE = 0
DEFAULT_TIMEOUT = 3


def parse_args():
    """Parse command line arguments using argparse."""
    parser = argparse.ArgumentParser(description=DESCRIPTION)

    parser.add_argument(
        '-V',
        '--version',
        action='version',
        version=f'%(prog)s: v{__version__} by {__author__}',
    )

    parser.add_argument(
        '--always-ok',
        help=lib.args.help('--always-ok'),
        dest='ALWAYS_OK',
        action='store_true',
        default=False,
    )

    parser.add_argument(
        '--cache-expire',
        help=lib.args.help('--cache-expire') + ' Default: %(default)s',
        dest='CACHE_EXPIRE',
        type=int,
        default=DEFAULT_CACHE_EXPIRE,
    )

    parser.add_argument(
        '--device-id',
        help='Huawei OceanStor Dorado API device ID.',
        dest='DEVICE_ID',
        required=True,
    )

    parser.add_argument(
        '--insecure',
        help=lib.args.help('--insecure'),
        dest='INSECURE',
        action='store_true',
        default=DEFAULT_INSECURE,
    )

    parser.add_argument(
        '--no-proxy',
        help=lib.args.help('--no-proxy'),
        dest='NO_PROXY',
        action='store_true',
        default=DEFAULT_NO_PROXY,
    )

    parser.add_argument(
        '--password',
        help='Huawei OceanStor Dorado API password.',
        dest='PASSWORD',
        required=True,
    )

    parser.add_argument(
        '--scope',
        help='Huawei OceanStor Dorado API scope.',
        dest='SCOPE',
        default=DEFAULT_SCOPE,
    )

    parser.add_argument(
        '--test',
        help=lib.args.help('--test'),
        dest='TEST',
        type=lib.args.csv,
    )

    parser.add_argument(
        '--timeout',
        help=lib.args.help('--timeout') + ' Default: %(default)s (seconds)',
        dest='TIMEOUT',
        type=int,
        default=DEFAULT_TIMEOUT,
    )

    parser.add_argument(
        '-u',
        '--url',
        help='Huawei OceanStor Dorado API URL.',
        dest='URL',
        required=True,
    )

    parser.add_argument(
        '--username',
        help='Huawei OceanStor Dorado API username.',
        dest='USERNAME',
        required=True,
    )

    args, _ = parser.parse_known_args()
    return args


def main():
    """The main function. This is where the magic happens."""

    # parse the command line
    try:
        args = parse_args()
    except SystemExit:
        sys.exit(STATE_UNKNOWN)

    if not args.URL.startswith('http'):
        lib.base.cu('--url parameter has to start with "http://" or https://".')

    # fetch data
    if args.TEST is None:
        result = lib.huawei.get_data('hypermetropair', args)
    else:
        # do not call the command, put in test data
        stdout, _stderr, _retc = lib.lftest.test(args.TEST)
        result = json.loads(stdout)

    # no valuable result?
    if not result:
        lib.base.cu(f'Got no valuable response from {args.URL}.')
    if result.get('error').get('code') != 0:
        lib.base.oao(
            f'{result.get("error").get("description")}'
            f' {result.get("error").get("suggestion")}',
            STATE_UNKNOWN,
        )

    # init some vars
    msg = ''
    state = STATE_OK
    perfdata = ''

    # analyze data
    table_data = []
    for hypermetropair in result.get('data'):
        health_state = STATE_OK
        if (
            lib.huawei.get_health_status(hypermetropair.get('HEALTHSTATUS'))
            != 'Normal (1)'
        ):
            health_state = STATE_WARN
            state = lib.base.get_worst(state, health_state)

        running_state = STATE_OK
        if (
            lib.huawei.get_running_status(hypermetropair.get('RUNNINGSTATUS'))
            != 'Normal (1)'
            and lib.huawei.get_running_status(hypermetropair.get('RUNNINGSTATUS'))
            != 'Synchronizing (23)'
        ):
            running_state = STATE_WARN
            state = lib.base.get_worst(state, running_state)

        linkstatus_state = STATE_OK
        if hypermetropair.get('LINKSTATUS') != '1':
            linkstatus_state = STATE_WARN
            state = lib.base.get_worst(state, linkstatus_state)

        localdata_state = STATE_OK
        if hypermetropair.get('LOCALDATASTATE') != '1':
            localdata_state = STATE_WARN
            state = lib.base.get_worst(state, localdata_state)

        remotedata_state = STATE_OK
        if hypermetropair.get('REMOTEDATASTATE') != '1':
            remotedata_state = STATE_WARN
            state = lib.base.get_worst(state, remotedata_state)

        hypermetropair['UUID'] = lib.huawei.get_uuid(hypermetropair)
        hypermetropair['sync_duration'] = int(hypermetropair['ENDTIME']) - int(
            hypermetropair['STARTTIME']
        )

        perfdata += lib.base.get_perfdata(
            f'{hypermetropair["UUID"]}_HEALTHSTATUS',
            hypermetropair['HEALTHSTATUS'],
            crit=2,
            _min=0,
            _max=2,
        )
        perfdata += lib.base.get_perfdata(
            f'{hypermetropair["UUID"]}_RUNNINGSTATUS',
            hypermetropair['RUNNINGSTATUS'],
            _min=0,
        )
        perfdata += lib.base.get_perfdata(
            f'{hypermetropair["UUID"]}_LINKSTATUS',
            hypermetropair['LINKSTATUS'],
            warn=2,
            _min=0,
            _max=2,
        )
        perfdata += lib.base.get_perfdata(
            f'{hypermetropair["UUID"]}_LOCALDATASTATE',
            hypermetropair['LOCALDATASTATE'],
            warn=2,
            _min=0,
            _max=2,
        )
        perfdata += lib.base.get_perfdata(
            f'{hypermetropair["UUID"]}_LOCALHOSTACCESSSTATE',
            hypermetropair['LOCALHOSTACCESSSTATE'],
            _min=0,
            _max=3,
        )
        perfdata += lib.base.get_perfdata(
            f'{hypermetropair["UUID"]}_REMOTEDATASTATE',
            hypermetropair['REMOTEDATASTATE'],
            warn=2,
            _min=0,
            _max=2,
        )
        perfdata += lib.base.get_perfdata(
            f'{hypermetropair["UUID"]}_REMOTEHOSTACCESSSTATE',
            hypermetropair['REMOTEHOSTACCESSSTATE'],
            _min=0,
            _max=5,
        )
        perfdata += lib.base.get_perfdata(
            f'{hypermetropair["UUID"]}_SYNCPROGRESS',
            hypermetropair['SYNCPROGRESS'],
            uom='%',
            _min=0,
            _max=100,
        )

        hypermetropair['health_state'] = lib.base.state2str(
            health_state, empty_ok=False
        )
        hypermetropair['running_state'] = lib.base.state2str(
            running_state, empty_ok=False
        )
        hypermetropair['sync_duration'] = (
            f'{lib.human.seconds2human(hypermetropair["sync_duration"])}'
        )
        hypermetropair['sync_last'] = (
            f'{lib.time.epoch2iso(int(hypermetropair["ENDTIME"]))}'
            f' ({lib.human.seconds2human(lib.time.now(as_type="epoch") - int(hypermetropair["ENDTIME"]))}'
            f' ago)'
        )
        hypermetropair['LINKSTATUS'] = lib.base.state2str(
            linkstatus_state, empty_ok=False
        )
        hypermetropair['LOCALDATASTATE'] = lib.base.state2str(
            localdata_state, empty_ok=False
        )
        hypermetropair['LOCALHOSTACCESSSTATE'] = lib.huawei.get_host_access_state(
            hypermetropair['LOCALHOSTACCESSSTATE']
        )
        hypermetropair['REMOTEDATASTATE'] = lib.base.state2str(
            remotedata_state, empty_ok=False
        )
        hypermetropair['REMOTEHOSTACCESSSTATE'] = lib.huawei.get_host_access_state(
            hypermetropair['REMOTEHOSTACCESSSTATE']
        )

        table_data.append(hypermetropair)

    if table_data:
        keys = [
            'UUID',
            'LINKSTATUS',
            'sync_last',
            'sync_duration',
            'SYNCPROGRESS',
            'LOCALOBJNAME',
            'LOCALDATASTATE',
            'LOCALHOSTACCESSSTATE',
            'REMOTEOBJNAME',
            'REMOTEDATASTATE',
            'REMOTEHOSTACCESSSTATE',
            'health_state',
            'running_state',
        ]
        headers = [
            'UUID',
            'Link',
            'Last Sync',
            'Duration',
            'Progr (%)',
            'LocalJob',
            'DataState',
            'Access',
            'RemoteJob',
            'DataState',
            'Access',
            'Health',
            'Running',
        ]

        # build the message
        msg += lib.base.get_table(table_data, keys, header=headers)

    msg += (
        f'\nFetched API {result.get("counter", 0)}'
        f' {lib.txt.pluralize("time", result.get("counter", 0))}'
    )

    if state == STATE_CRIT:
        msg = 'There are critical errors.\n\n' + msg
    elif state == STATE_WARN:
        msg = 'There are warnings.\n\n' + msg
    else:
        msg = 'Everything is ok.\n\n' + msg

    # over and out
    lib.base.oao(msg, state, perfdata, always_ok=args.ALWAYS_OK)


if __name__ == '__main__':
    try:
        main()
    except Exception:
        lib.base.cu()
