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

import lib.args
import lib.base
import lib.cache
import lib.lftest
import lib.net
import lib.time
import lib.txt
from lib.globals import STATE_OK, STATE_UNKNOWN

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

DESCRIPTION = """Monitors account statistics of a Starface PBX via its monitoring
module on port 6556. Reports SIP and DAHDI account states including registered,
unregistered, and failed accounts. Supports both IPv4 and IPv6. Data is cached to
avoid overloading the PBX when multiple checks run in parallel."""

DEFAULT_CACHE_EXPIRE = 1  # minutes
DEFAULT_HOSTNAME = 'localhost'
DEFAULT_IPV6 = False
DEFAULT_PORT = 6556
DEFAULT_TIMEOUT = 8  # seconds


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(
        '--cache-expire',
        help=lib.args.help('--cache-expire') + ' Default: %(default)s',
        dest='CACHE_EXPIRE',
        type=int,
        default=DEFAULT_CACHE_EXPIRE,
    )

    parser.add_argument(
        '-H',
        '--hostname',
        help='Starface PBX hostname or IP address. Default: %(default)s',
        dest='HOSTNAME',
        default=DEFAULT_HOSTNAME,
    )

    parser.add_argument(
        '--port',
        help='Starface PBX monitoring port. Default: %(default)s',
        dest='PORT',
        type=int,
        default=DEFAULT_PORT,
    )

    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(
        '--ipv6',
        help=lib.args.help('--ipv6'),
        dest='USE_IPV6',
        action='store_true',
        default=DEFAULT_IPV6,
    )

    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:
        # fetch data from PBX, but first from cache
        data = lib.cache.get(
            args.HOSTNAME, filename='linuxfabrik-monitoring-plugins-starface.db'
        )
        if not data:
            data = lib.base.coe(
                lib.net.fetch(args.HOSTNAME, args.PORT, timeout=args.TIMEOUT)
            )
            lib.cache.set(
                args.HOSTNAME,
                data,
                lib.time.now() + args.CACHE_EXPIRE * 60,
                filename='linuxfabrik-monitoring-plugins-starface.db',
            )
    else:
        # do not call the command, put in test data
        stdout, _, _ = lib.lftest.test(args.TEST)
        data = stdout

    if not data:
        lib.base.cu(f'Got no valuable response from {args.HOSTNAME}:{args.PORT}.')

    # extract data
    result = lib.txt.extract_str(data, '<<<starface_accounts>>>', '<<<').splitlines()

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

    # analyze data
    active_accounts = 0
    admin_accounts = 0
    available_accounts = 0
    ringing_accounts = 0
    total_accounts = 0
    unavailable_accounts = 0
    for row in result:
        if not row:
            continue
        if row.startswith('total_accounts'):
            total_accounts = row.replace('total_accounts ', '').replace('/0', '')
        if row.startswith('admin_accounts'):
            admin_accounts = row.replace('admin_accounts ', '')
        if row.startswith('active_accounts'):
            active_accounts = row.replace('active_accounts ', '')
        if row.startswith('available_accounts'):
            available_accounts = row.replace('available_accounts ', '')
        if row.startswith('ringing_accounts'):
            ringing_accounts = row.replace('ringing_accounts ', '')
        if row.startswith('unavailable_accounts'):
            unavailable_accounts = row.replace('unavailable_accounts ', '')

    # build the message
    msg += (
        f'{ringing_accounts} ringing, '
        f'{active_accounts} active, '
        f'{available_accounts} available'
        f'{f", {unavailable_accounts} unavailable" if unavailable_accounts else ""}'
        f' (total {total_accounts} '
        f'{lib.txt.pluralize("account", total_accounts)})\n'
        f'{admin_accounts} of them are admin accounts'
    )

    perfdata += lib.base.get_perfdata(
        'active_accounts',
        active_accounts,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'admin_accounts',
        admin_accounts,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'available_accounts',
        available_accounts,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'ringing_accounts',
        ringing_accounts,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'total_accounts',
        total_accounts,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'unavailable_accounts',
        unavailable_accounts,
        _min=0,
    )

    # over and out
    lib.base.oao(msg, state, perfdata)


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