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

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

DESCRIPTION = """Checks the overall health of a Starface PBX via its monitoring module on port 6556.
Reports system state, version, and license information. Supports both IPv4 and IPv6.
Data is cached to avoid overloading the PBX when multiple checks run in parallel.
Alerts when the PBX reports a non-healthy system state."""

DEFAULT_CACHE_EXPIRE = 1  # minutes
DEFAULT_CRIT = 90  # %
DEFAULT_HOSTNAME = 'localhost'
DEFAULT_IPV6 = False
DEFAULT_PORT = 6556
DEFAULT_TIMEOUT = 8  # seconds
DEFAULT_WARN = 80  # %


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(
        '--critical',
        help=lib.args.help('--critical') + ' Default: >= %(default)s',
        dest='CRIT',
        default=DEFAULT_CRIT,
    )

    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(
        '--warning',
        help=lib.args.help('--warning') + ' Default: >= %(default)s',
        dest='WARN',
        default=DEFAULT_WARN,
    )

    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, _stderr, _retc = 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>>>', '<<<').splitlines()

    # init some vars
    msg_header, msg_body = '', ''
    state = STATE_OK
    perfdata = ''

    # build the message
    for row in result:
        if not row:
            continue

        if row.startswith('appliance_type'):
            value = row.replace('appliance_type ', '').replace('"', '')
            msg_header += f'{value}, '

        if row.startswith('appliance_max_users'):
            value = row.replace('appliance_max_users ', '')
            if value != '0':
                msg_body += f'{value} max users, '
                perfdata += lib.base.get_perfdata(
                    'appliance_max_users',
                    value,
                    _min=0,
                )

        if row.startswith('appliance_max_connections'):
            value = row.replace('appliance_max_connections ', '')
            if value != '0':
                msg_body += f'{value} max conns, '
                perfdata += lib.base.get_perfdata(
                    'appliance_max_connections',
                    value,
                    _min=0,
                )

        if row.startswith('starface_version'):
            value = row.replace('starface_version ', '')
            msg_header += f'v{value}, '
            perfdata = lib.base.get_perfdata(
                'starface_version',
                lib.version.version2float(value),
                _min=0,
            )

        if row.startswith('owner'):
            value = row.replace('owner ', '')
            msg_body += f'Owner: {value}, '.replace('"', '')

        if row.startswith('license_max_users'):
            value = row.replace('license_max_users ', '')
            msg_body += f'{value} licensed {lib.txt.pluralize("user", value)}, '

        if row.startswith('raid_diagnosis'):
            value = row.replace('raid_diagnosis ', '')
            if value == 'HEALTHY':
                raid_status = STATE_OK
            else:
                raid_status = STATE_WARN
                state = lib.base.get_worst(STATE_WARN, state)
            msg_header += (
                f'RAID Status: {value}{lib.base.state2str(raid_status, prefix=" ")}, '
            )

        if row.startswith('blacklisted_hosts'):
            value = row.replace('blacklisted_hosts ', '')
            msg_header += f'{value} blacklisted {lib.txt.pluralize("host", value)}, '
            perfdata += lib.base.get_perfdata(
                'blacklisted_hosts',
                value,
                _min=0,
            )

        if row.startswith('whitelisted_hosts'):
            value = row.replace('whitelisted_hosts ', '')
            msg_body += f'{value} whitelisted {lib.txt.pluralize("host", value)}, '
            perfdata += lib.base.get_perfdata(
                'whitelisted_hosts',
                value,
                _min=0,
            )

        if row.startswith('sip_status_localhost'):
            value = row.replace('sip_status_localhost ', '')
            if value == 'OK':
                sip_status = STATE_OK
            else:
                sip_status = STATE_WARN
                state = lib.base.get_worst(STATE_WARN, state)
            msg_header += (
                f'SIP Status: {value}{lib.base.state2str(sip_status, prefix=" ")}, '
            )

        if row.startswith('known_phones'):
            value = row.replace('known_phones ', '')
            msg_body += f'{value} {lib.txt.pluralize("phone", value)} known, '
            perfdata += lib.base.get_perfdata(
                'known_phones',
                value,
                _min=0,
            )

        if row.startswith('online_phones'):
            value = row.replace('online_phones ', '')
            msg_header += f'{value} {lib.txt.pluralize("phone", value)} online, '
            perfdata += lib.base.get_perfdata(
                'online_phones',
                value,
                _min=0,
            )

        if row.startswith('ip_changed_phones'):
            value = row.replace('ip_changed_phones ', '')
            msg_body += f'{value} {lib.txt.pluralize("phone", value)} changed IP, '
            perfdata += lib.base.get_perfdata(
                'ip_changed_phones',
                value,
                _min=0,
            )

        if row.startswith('asterisk_uptime'):
            value = row.replace('asterisk_uptime ', '')
            msg_body += f'Up {value.strip()}, '

    # over and out
    msg = f'{msg_header[:-2]}\n{msg_body[:-2]}'
    lib.base.oao(msg, state, perfdata, always_ok=args.ALWAYS_OK)


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