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

import lib.args
import lib.base
import lib.human
import lib.txt
import lib.url
from lib.globals import STATE_OK, STATE_UNKNOWN

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

DESCRIPTION = """Monitors Nextcloud usage statistics via the server info API, including active user
counts over time, file shares by category, and storage metrics."""

DEFAULT_INSECURE = False
DEFAULT_NO_PROXY = False
DEFAULT_TIMEOUT = 8
DEFAULT_URL = 'http://localhost/nextcloud/ocs/v2.php/apps/serverinfo/api/v1/info'
DEFAULT_USERNAME = 'admin'


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(
        '--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='Password for authenticating against the Nextcloud API.',
        dest='PASSWORD',
        required=True,
    )

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

    parser.add_argument(
        '--username',
        help='Username for authenticating against the Nextcloud API. '
        'Default: %(default)s',
        dest='USERNAME',
        default=DEFAULT_USERNAME,
    )

    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://".')
    if not args.URL.endswith('/info'):
        lib.base.cu('--url parameter has to end in "/info".')
    url = args.URL + '?format=json&skipApps=false'

    # Add the authentication and api request header
    auth = f'{args.USERNAME}:{args.PASSWORD}'
    encoded_auth = lib.txt.to_text(base64.b64encode(lib.txt.to_bytes(auth)))
    header = {
        'Authorization': f'Basic {encoded_auth}',
        'OCS-APIRequest': 'true',
    }
    # and get the info from the API
    jsonst = lib.base.coe(
        lib.url.fetch(
            url,
            header=header,
            insecure=args.INSECURE,
            no_proxy=args.NO_PROXY,
            timeout=args.TIMEOUT,
        )
    )
    try:
        result = json.loads(jsonst)
    except Exception:
        lib.base.cu('ValueError: No JSON object could be decoded')

    if result['ocs']['meta']['status'] != 'ok':
        lib.base.cu('Sorry, something went wrong - no "ok" state returned.')

    # extract some application specific data
    nc_system_apps_num_installed = result['ocs']['data']['nextcloud']['system']['apps'][
        'num_installed'
    ]
    nc_system_apps_num_updates_available = result['ocs']['data']['nextcloud']['system'][
        'apps'
    ]['num_updates_available']
    nc_system_memcache_local = result['ocs']['data']['nextcloud']['system'][
        'memcache.local'
    ]
    nc_system_memcache_locking = result['ocs']['data']['nextcloud']['system'][
        'memcache.locking'
    ]
    nc_system_version = result['ocs']['data']['nextcloud']['system']['version']

    nc_storage_num_users = result['ocs']['data']['nextcloud']['storage']['num_users']
    nc_storage_num_files = result['ocs']['data']['nextcloud']['storage']['num_files']
    nc_storage_num_storages = result['ocs']['data']['nextcloud']['storage'][
        'num_storages'
    ]
    nc_storage_num_storages_local = result['ocs']['data']['nextcloud']['storage'][
        'num_storages_local'
    ]
    nc_storage_num_storages_home = result['ocs']['data']['nextcloud']['storage'][
        'num_storages_home'
    ]
    nc_storage_num_storages_other = result['ocs']['data']['nextcloud']['storage'][
        'num_storages_other'
    ]

    nc_shares_num_fed_shares_received = result['ocs']['data']['nextcloud']['shares'][
        'num_fed_shares_received'
    ]
    nc_shares_num_fed_shares_sent = result['ocs']['data']['nextcloud']['shares'][
        'num_fed_shares_sent'
    ]

    nc_shares_num_shares = result['ocs']['data']['nextcloud']['shares']['num_shares']
    nc_shares_num_shares_groups = result['ocs']['data']['nextcloud']['shares'][
        'num_shares_groups'
    ]
    nc_shares_num_shares_link = result['ocs']['data']['nextcloud']['shares'][
        'num_shares_link'
    ]
    nc_shares_num_shares_link_no_password = result['ocs']['data']['nextcloud'][
        'shares'
    ]['num_shares_link_no_password']
    nc_shares_num_shares_mail = (
        result['ocs']['data']['nextcloud']['shares'].get('num_shares_mail', 'n/a')
    )
    nc_shares_num_shares_room = (
        result['ocs']['data']['nextcloud']['shares'].get('num_shares_room', 'n/a')
    )
    nc_shares_num_shares_user = result['ocs']['data']['nextcloud']['shares'][
        'num_shares_user'
    ]

    nc_server_php_max_execution_time = result['ocs']['data']['server']['php'][
        'max_execution_time'
    ]
    nc_server_php_memory_limit = result['ocs']['data']['server']['php']['memory_limit']
    nc_server_php_upload_max_filesize = result['ocs']['data']['server']['php'][
        'upload_max_filesize'
    ]
    nc_server_php_version = result['ocs']['data']['server']['php']['version']
    nc_server_webserver = result['ocs']['data']['server']['webserver']

    nc_server_database_size = int(result['ocs']['data']['server']['database']['size'])
    nc_server_database_type = result['ocs']['data']['server']['database']['type']
    nc_server_database_version = result['ocs']['data']['server']['database']['version']

    nc_active_users_last5min = result['ocs']['data']['activeUsers']['last5minutes']
    nc_active_users_last1h = result['ocs']['data']['activeUsers']['last1hour']
    nc_active_users_last24h = result['ocs']['data']['activeUsers']['last24hours']

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

    # build the (long) multiline message
    msg += (
        f'{nc_storage_num_users} users'
        f' ({nc_active_users_last5min}'
        f'/{nc_active_users_last1h}'
        f'/{nc_active_users_last24h}'
        f' in the last 5min/1h/24h),'
        f' {lib.human.number2human(nc_storage_num_files)} files,'
        f' {nc_system_apps_num_installed} apps'
        f' ({nc_system_apps_num_updates_available}'
        f' {lib.txt.pluralize("update", nc_system_apps_num_updates_available)}'
        f' available),'
        f' v{nc_system_version}\n'
    )

    # build the message
    msg += (
        f'* Shares: {nc_shares_num_shares}'
        f' ({nc_shares_num_shares_groups}'
        f' {lib.txt.pluralize("group", nc_shares_num_shares_groups)},'
        f' {nc_shares_num_shares_link}'
        f' {lib.txt.pluralize("link", nc_shares_num_shares_link)}'
        f' [{nc_shares_num_shares_link_no_password} w/o password],'
        f' {nc_shares_num_shares_mail}'
        f' {lib.txt.pluralize("mail", nc_shares_num_shares_mail)},'
        f' {nc_shares_num_shares_room}'
        f' {lib.txt.pluralize("room", nc_shares_num_shares_room)},'
        f' {nc_shares_num_shares_user}'
        f' {lib.txt.pluralize("user", nc_shares_num_shares_user)},'
        f' {nc_shares_num_fed_shares_sent}'
        f' federated sent)\n'
    )
    msg += f'* Federated Shares: {nc_shares_num_fed_shares_received} received\n'
    msg += (
        f'* Storages: {nc_storage_num_storages}'
        f' ({nc_storage_num_storages_home} home,'
        f' {nc_storage_num_storages_other} other,'
        f' {nc_storage_num_storages_local} local)\n'
    )
    msg += (
        f'* PHP: v{nc_server_php_version},'
        f' upload_max_filesize='
        f'{lib.human.bytes2human(nc_server_php_upload_max_filesize)},'
        f' max_execution_time='
        f'{nc_server_php_max_execution_time}s,'
        f' memory_limit='
        f'{lib.human.bytes2human(nc_server_php_memory_limit)}\n'
    )
    msg += (
        f'* DB: {nc_server_database_type}'
        f' v{nc_server_database_version},'
        f' size='
        f'{lib.human.bytes2human(nc_server_database_size)}\n'
    )
    local_mc = nc_system_memcache_local.replace('\\OC\\', '')
    locking_mc = nc_system_memcache_locking.replace('\\OC\\', '')
    msg += (
        f'* Web: {nc_server_webserver},'
        f' local memcache: {local_mc},'
        f' locking memcache: {locking_mc}'
    )

    perfdata += lib.base.get_perfdata(
        'nc_system_apps_num_installed',
        nc_system_apps_num_installed,
        _min=0,
    )

    perfdata += lib.base.get_perfdata(
        'nc_storage_num_users',
        nc_storage_num_users,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'nc_storage_num_files',
        nc_storage_num_files,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'nc_storage_num_storages',
        nc_storage_num_storages,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'nc_storage_num_storages_local',
        nc_storage_num_storages_local,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'nc_storage_num_storages_home',
        nc_storage_num_storages_home,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'nc_storage_num_storages_other',
        nc_storage_num_storages_other,
        _min=0,
    )

    perfdata += lib.base.get_perfdata(
        'nc_shares_num_fed_shares_received',
        nc_shares_num_fed_shares_received,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'nc_shares_num_fed_shares_sent',
        nc_shares_num_fed_shares_sent,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'nc_shares_num_shares',
        nc_shares_num_shares,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'nc_shares_num_shares_groups',
        nc_shares_num_shares_groups,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'nc_shares_num_shares_link',
        nc_shares_num_shares_link,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'nc_shares_num_shares_link_no_password',
        nc_shares_num_shares_link_no_password,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'nc_shares_num_shares_mail',
        nc_shares_num_shares_mail,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'nc_shares_num_shares_room',
        nc_shares_num_shares_room,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'nc_shares_num_shares_user',
        nc_shares_num_shares_user,
        _min=0,
    )

    perfdata += lib.base.get_perfdata(
        'nc_server_database_size',
        nc_server_database_size,
        uom='B',
        _min=0,
    )

    perfdata += lib.base.get_perfdata(
        'nc_active_users_last5min',
        nc_active_users_last5min,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'nc_active_users_last1h',
        nc_active_users_last1h,
        _min=0,
    )
    perfdata += lib.base.get_perfdata(
        'nc_active_users_last24h',
        nc_active_users_last24h,
        _min=0,
    )

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


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