#!/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 time

import lib.args
import lib.base
import lib.lftest
import lib.time
import lib.url
from lib.globals import STATE_UNKNOWN

__author__ = """Linuxfabrik GmbH, Zurich/Switzerland;
                originally written by Dominik Riva, Universitätsspital Basel/Switzerland"""
__version__ = '2026040801'


DESCRIPTION = """Checks availability and response time of an ID DIACOS installation by performing a
full login, diagnosis search, and logout cycle. Alerts if the total response time
exceeds the configured thresholds. Useful for monitoring the health of DIACOS medical
billing systems."""

DEFAULT_COMPUTER = 'Brower_APP'
DEFAULT_CONCEPT_FILTER = '%25R239%3BC%3BD99.99'
DEFAULT_COUNTRY = 'CH'
DEFAULT_CRITICAL = 6000  # ms
DEFAULT_FORMAT = '%25T0%25C%3F%25I%25R'
DEFAULT_INSECURE = False
DEFAULT_IP = '127.0.0.1'
DEFAULT_NO_PROXY = False
DEFAULT_SEARCHTEXT = 'Haut'
DEFAULT_SORT_MODE = '%25T'
DEFAULT_TIMEOUT = 7
DEFAULT_URL = 'http://localhost:9999'
DEFAULT_WARNING = 3000  # ms
DEFAULT_YEAR = '2020'


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(
        '-c',
        '--critical',
        help='CRIT threshold for the total duration of login, search, and logout, in milliseconds. '
        'Default: %(default)s',
        dest='CRITICAL',
        type=int,
        default=DEFAULT_CRITICAL,
    )

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

    parser.add_argument(
        '--login-computer',
        help='COMPUTER argument for the user.Login API call. Default: %(default)s',
        dest='COMPUTER',
        default=DEFAULT_COMPUTER,
    )

    parser.add_argument(
        '--login-ip',
        help='IP argument for the user.Login API call. Default: %(default)s',
        dest='IP',
        default=DEFAULT_IP,
    )

    parser.add_argument(
        '--login-licence',
        help='LICENCE argument for the user.Login API call (required).',
        dest='LICENCE',
        required=True,
    )

    parser.add_argument(
        '--login-name',
        help='NAME argument for the user.Login API call (required).',
        dest='NAME',
        required=True,
    )

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

    parser.add_argument(
        '--search-concept-filter',
        help='CONCEPT_FILTER argument for the classification.SearchDiagnoses API call. '
        'Default: %(default)s',
        dest='CONCEPT_FILTER',
        default=DEFAULT_CONCEPT_FILTER,
    )

    parser.add_argument(
        '--search-country',
        help='COUNTRY argument for the classification.SearchDiagnoses API call. '
        'Default: %(default)s',
        dest='COUNTRY',
        default=DEFAULT_COUNTRY,
    )

    parser.add_argument(
        '--search-format',
        help='FORMAT argument for the classification.SearchDiagnoses API call. '
        'Default: %(default)s',
        dest='FORMAT',
        default=DEFAULT_FORMAT,
    )

    parser.add_argument(
        '--search-searchtext',
        help='SEARCHTEXT argument for the classification.SearchDiagnoses API call. '
        'Default: %(default)s',
        dest='SEARCHTEXT',
        default=DEFAULT_SEARCHTEXT,
    )

    parser.add_argument(
        '--search-sort-mode',
        help='SORT_MODE argument for the classification.SearchDiagnoses API call. '
        'Default: %(default)s',
        dest='SORT_MODE',
        default=DEFAULT_SORT_MODE,
    )

    parser.add_argument(
        '--search-year',
        help='YEAR argument for the classification.SearchDiagnoses API call. '
        'Default: %(default)s',
        dest='YEAR',
        default=DEFAULT_YEAR,
    )

    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(
        '--url',
        help='ID DIACOS base URL. Default: %(default)s',
        dest='URL',
        default=DEFAULT_URL,
    )

    parser.add_argument(
        '-w',
        '--warning',
        help='WARN threshold for the total duration of login, search, and logout, in milliseconds. '
        'Default: %(default)s',
        dest='WARNING',
        type=int,
        default=DEFAULT_WARNING,
    )

    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)

    # fetch data
    if args.TEST is None:
        start_time = time.time()

        url = (
            f'{args.URL}/axis2/idlogikrest'
            f'?__format__=json'
            f'&serviceName=user.Login'
            f'&COMPUTER={args.COMPUTER}'
            f'&IP={args.IP}'
            f'&NAME={args.NAME}'
            f'&LICENCE={args.LICENCE}'
        )
        session = lib.base.coe(
            lib.url.fetch_json(
                url,
                insecure=args.INSECURE,
                no_proxy=args.NO_PROXY,
                timeout=args.TIMEOUT,
            )
        )
        session_id = session['resultItems'][0]['value']
        if len(session_id) < 32 + 1 + len(args.NAME):
            lib.base.cu(f'Session-ID {session_id} too short')
        login_duration = session['totalTimeMillis']

        url = (
            f'{args.URL}/axis2/idlogikrest'
            f'?__format__=json'
            f'&serviceName='
            f'classification.SearchDiagnoses'
            f'&COUNTRY={args.COUNTRY}'
            f'&YEAR={args.YEAR}'
            f'&FORMAT={args.FORMAT}'
            f'&SORT_MODE={args.SORT_MODE}'
            f'&CONCEPT_FILTER={args.CONCEPT_FILTER}'
            f'&SESSION_ID={session_id}'
            f'&SEARCHTEXT={args.SEARCHTEXT}'
        )
        search_result = lib.base.coe(
            lib.url.fetch_json(
                url,
                insecure=args.INSECURE,
                no_proxy=args.NO_PROXY,
                timeout=args.TIMEOUT,
            )
        )
        search_duration = search_result['totalTimeMillis']

        url = (
            f'{args.URL}/axis2/idlogikrest'
            f'?__format__=json'
            f'&serviceName=user.Logoff'
            f'&SESSION_ID={session_id}'
        )
        logout_result = lib.base.coe(
            lib.url.fetch_json(
                url,
                insecure=args.INSECURE,
                no_proxy=args.NO_PROXY,
                timeout=args.TIMEOUT,
            )
        )
        logout_duration = logout_result['totalTimeMillis']

        runtime = (time.time() - start_time) * 1000  # we get seconds and want ms
    else:
        # do not call the command, put in test data
        args.TEST[0] += '-login'
        stdout, _stderr, _retc = lib.lftest.test(args.TEST)
        result = json.loads(stdout)
        login_duration = result['totalTimeMillis']

        args.TEST[0] = args.TEST[0].replace('-login', '-searchDiagnoses')
        stdout, _stderr, _retc = lib.lftest.test(args.TEST)
        result = json.loads(stdout)
        search_duration = result['totalTimeMillis']

        args.TEST[0] = args.TEST[0].replace('-searchDiagnoses', '-logoff')
        stdout, _stderr, _retc = lib.lftest.test(args.TEST)
        result = json.loads(stdout)
        logout_duration = result['totalTimeMillis']

        runtime = login_duration + search_duration + logout_duration

    # build the message
    state = lib.base.get_state(runtime, args.WARNING, args.CRITICAL)
    msg = (
        f'{round(runtime, 2)}ms for login, search'
        f' and logout'
        f'{lib.base.state2str(state, prefix=" ")}'
    )
    perfdata = lib.base.get_perfdata(
        'runtime',
        runtime,
        uom='ms',
        warn=args.WARNING,
        crit=args.CRITICAL,
        _min=0,
        _max=args.TIMEOUT * 1000,
    )
    perfdata += lib.base.get_perfdata(
        'login_duration',
        login_duration,
        uom='ms',
        _min=0,
        _max=args.TIMEOUT * 1000,
    )
    perfdata += lib.base.get_perfdata(
        'search_duration',
        search_duration,
        uom='ms',
        _min=0,
        _max=args.TIMEOUT * 1000,
    )
    perfdata += lib.base.get_perfdata(
        'logout_duration',
        logout_duration,
        uom='ms',
        _min=0,
        _max=args.TIMEOUT * 1000,
    )

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


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