#!/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.lftest
import lib.url
from lib.globals import STATE_OK, STATE_UNKNOWN, STATE_WARN

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

DESCRIPTION = """Monitors the health and performance of an Axenita/Achilles installation by querying
four API endpoints: ReadModel state, active user sessions, build information, and
maintenance mode status. Alerts if any endpoint returns an error, if the ReadModel
initialization is incomplete, or if maintenance mode is active."""

DEFAULT_INSECURE = False
DEFAULT_NO_PROXY = False
DEFAULT_TIMEOUT = 3
DEFAULT_URL = 'http://localhost:10000/achilles/ar'


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(
        '--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(
        '--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='Axenita API URL. Default: %(default)s',
        dest='URL',
        default=DEFAULT_URL,
    )

    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
    achilles_readmodel = ''
    achilles_userinfo = ''
    achilles_buildinfo = ''
    achilles_maintenance = ''

    # fetch data, get axenita info
    if args.TEST is None:
        achilles_readmodel = lib.base.coe(
            lib.url.fetch_json(
                args.URL + '/api/admin/readmodel/state',
                insecure=args.INSECURE,
                no_proxy=args.NO_PROXY,
                timeout=args.TIMEOUT,
            )
        )
        achilles_userinfo = lib.base.coe(
            lib.url.fetch_json(
                args.URL + '/api/admin/user-info/number-of-current-sessions',
                insecure=args.INSECURE,
                no_proxy=args.NO_PROXY,
                timeout=args.TIMEOUT,
            )
        )
        achilles_buildinfo = lib.base.coe(
            lib.url.fetch_json(
                args.URL + '/api/build-info',
                insecure=args.INSECURE,
                no_proxy=args.NO_PROXY,
                timeout=args.TIMEOUT,
            )
        )
        achilles_maintenance = lib.base.coe(
            lib.url.fetch_json(
                args.URL + '/api/login/maintenance-state-active',
                insecure=args.INSECURE,
                no_proxy=args.NO_PROXY,
                timeout=args.TIMEOUT,
            )
        )
    else:
        # do not call the command, put in test data
        stdout, _, _ = lib.lftest.test(args.TEST)

        try:
            stdout = json.loads(stdout)
        except Exception:
            lib.base.cu('ValueError: No JSON object could be decoded')

        if 'readmodel' in args.TEST[0]:
            achilles_readmodel = stdout
        if 'userinfo' in args.TEST[0]:
            achilles_userinfo = stdout
        if 'buildinfo' in args.TEST[0]:
            achilles_buildinfo = stdout
        if 'maintenance' in args.TEST[0]:
            achilles_maintenance = stdout

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

    # analyze data
    if achilles_maintenance:
        if achilles_maintenance['state'].upper() != 'SUCCESS':
            state = lib.base.get_worst(STATE_WARN, state)
            msg = (
                f'{args.URL}/api/login/maintenance-state-active, '
                f'state: {achilles_maintenance["state"]}'
                f'{lib.base.state2str(state)}'
            )
            lib.base.oao(msg, state, perfdata, always_ok=args.ALWAYS_OK)
        if achilles_maintenance['data'] is not False:
            state = lib.base.get_worst(STATE_WARN, state)

            # build the message
            msg += (
                f'Axenita/Achilles is in maintenance mode {lib.base.state2str(state)}, '
            )
            perfdata += lib.base.get_perfdata(
                'maintenance',
                1,
                _min=0,
                _max=1,
            )
        else:
            perfdata += lib.base.get_perfdata(
                'maintenance',
                0,
                _min=0,
                _max=1,
            )

    if achilles_readmodel:
        if achilles_readmodel['state'].upper() != 'SUCCESS':
            state = lib.base.get_worst(STATE_WARN, state)
            msg = (
                f'{args.URL}/api/admin/readmodel/state, '
                f'state: {achilles_readmodel["state"]}'
                f'{lib.base.state2str(state)}'
            )
            lib.base.oao(msg, state, perfdata, always_ok=args.ALWAYS_OK)
        if achilles_readmodel['data']['readModelState'].upper() != 'DONE':
            state = lib.base.get_worst(STATE_WARN, state)
            rm_state = achilles_readmodel['data']['readModelState']
            msg = (
                f'{args.URL}/api/admin/readmodel/state, '
                f'data.readModelState: {rm_state}'
                f'{lib.base.state2str(state)}'
            )
            lib.base.oao(msg, state, perfdata, always_ok=args.ALWAYS_OK)
        msg += f'ReadModel: {achilles_readmodel["data"]["message"]}, '
        perfdata += lib.base.get_perfdata(
            'currentInitRmStep',
            achilles_readmodel['data']['currentInitRmStep'],
            _min=0,
        )
        perfdata += lib.base.get_perfdata(
            'totalInitRmSteps',
            achilles_readmodel['data']['totalInitRmSteps'],
            _min=0,
        )
        perfdata += lib.base.get_perfdata(
            'totalDurationInitRm',
            achilles_readmodel['data']['totalDurationInitRm'],
            _min=0,
        )

    if achilles_userinfo:
        if achilles_userinfo['state'].upper() != 'SUCCESS':
            state = lib.base.get_worst(STATE_WARN, state)
            msg = (
                f'{args.URL}/api/admin/user-info/'
                f'number-of-current-sessions, '
                f'state: {achilles_userinfo["state"]}'
                f'{lib.base.state2str(state)}'
            )
            lib.base.oao(msg, state, perfdata, always_ok=args.ALWAYS_OK)
        logged_in = achilles_userinfo['data']['loggedInUsers']
        sessions = achilles_userinfo['data']['currentActiveSessions']
        msg += f'{logged_in} users logged in, {sessions} active sessions, '
        perfdata += lib.base.get_perfdata(
            'loggedInUsers',
            achilles_userinfo['data']['loggedInUsers'],
            _min=0,
        )
        perfdata += lib.base.get_perfdata(
            'currentActiveSessions',
            achilles_userinfo['data']['currentActiveSessions'],
            _min=0,
        )

    if achilles_buildinfo:
        if achilles_buildinfo['state'].upper() != 'SUCCESS':
            state = lib.base.get_worst(STATE_WARN, state)
            msg = (
                f'{args.URL}/api/build-info, '
                f'state: {achilles_buildinfo["state"]}'
                f'{lib.base.state2str(state)}'
            )
            lib.base.oao(msg, state, perfdata, always_ok=args.ALWAYS_OK)
        axenita_ver = achilles_buildinfo['data']['version']
        msg += f'{axenita_ver} (timestamp {achilles_buildinfo["data"]["timestamp"]}), '
        # the version field looks like "release-14.0.8-20210312134147-cf77b213090";
        # take the second hyphen-separated segment (the dotted version) and collapse
        # the dots to get a numeric perfdata value. the previous slice
        # `[8 : 8 + find('-') - 1]` happened to work only for exactly-6-char
        # versions like "14.0.8" and silently truncated multi-digit patches.
        version_parts = axenita_ver.split('-')
        if len(version_parts) >= 2:
            axenita_ver = version_parts[1].replace('.', '')
        else:
            axenita_ver = ''
        perfdata += lib.base.get_perfdata(
            'axenita-version',
            axenita_ver,
            _min=0,
        )

    # over and out
    lib.base.oao(msg[:-2], state, perfdata, always_ok=args.ALWAYS_OK)


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