#!/usr/lib64/linuxfabrik-monitoring-plugins/venv/bin/python
# -*- 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 os
import re
import sys

import lib.args
import lib.base
import lib.disk
import lib.version
from lib.globals import STATE_UNKNOWN

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

DESCRIPTION = """Checks the installed Matomo version against the endoflife.date API and alerts if the
version is end-of-life or if newer major, minor, or patch releases are available. By
default, alerts 30 days before the official EOL date. The offset is configurable."""

DEFAULT_CHECK_MAJOR = False
DEFAULT_CHECK_MINOR = False
DEFAULT_CHECK_PATCH = False
DEFAULT_INSECURE = False
DEFAULT_NO_PROXY = False
DEFAULT_OFFSET_EOL = -30  # days
DEFAULT_PATH = '/var/www/html/matomo'
DEFAULT_TIMEOUT = 3
DEFAULT_UNREACHABLE_SEVERITY = 'ok'


def parse_args():
    """Parse command line arguments using argparse."""
    parser = argparse.ArgumentParser(
        description=DESCRIPTION,
        epilog=lib.args.epilog(__file__),
        formatter_class=lib.args.HelpFormatter,
    )

    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',  # deprecated parameter
        help=argparse.SUPPRESS,
        dest='CACHE_EXPIRE',
        type=int,
    )

    parser.add_argument(
        '--check-major',
        help=lib.args.help('--check-major'),
        dest='CHECK_MAJOR',
        action='store_true',
        default=DEFAULT_CHECK_MAJOR,
    )

    parser.add_argument(
        '--check-minor',
        help=lib.args.help('--check-minor'),
        dest='CHECK_MINOR',
        action='store_true',
        default=DEFAULT_CHECK_MINOR,
    )

    parser.add_argument(
        '--check-patch',
        help=lib.args.help('--check-patch'),
        dest='CHECK_PATCH',
        action='store_true',
        default=DEFAULT_CHECK_PATCH,
    )

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

    parser.add_argument(
        '--no-perfdata',
        help=lib.args.help('--no-perfdata'),
        dest='NO_PERFDATA',
        action='store_true',
        default=False,
    )

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

    parser.add_argument(
        '--offset-eol',
        help=lib.args.help('--offset-eol') + ' Default: %(default)s days',
        dest='OFFSET_EOL',
        type=int,
        default=DEFAULT_OFFSET_EOL,
    )

    parser.add_argument(
        '--path',
        help='Local path to your Matomo/Piwik installation, typically within your '
        "Webserver's Document Root. "
        'Default: %(default)s',
        dest='PATH',
        default=DEFAULT_PATH,
    )

    parser.add_argument(
        '--proxy',
        help=lib.args.help('--proxy'),
        dest='PROXY',
        default=None,
    )

    parser.add_argument(
        '--timeout',
        help=lib.args.help('--timeout') + ' Default: %(default)s (seconds)',
        dest='TIMEOUT',
        type=int,
        default=DEFAULT_TIMEOUT,
    )

    parser.add_argument(
        '--unreachable-severity',
        help=lib.args.help('--unreachable-severity') + ' Default: %(default)s',
        dest='UNREACHABLE_SEVERITY',
        choices=['ok', 'warn', 'crit', 'unknown'],
        default=DEFAULT_UNREACHABLE_SEVERITY,
    )

    args, _ = parser.parse_known_args()
    return args


def get_installed_version(args):
    # core/Version.php: `const VERSION = '4.16.0';` (Piwik 0.2.10 to Matomo 5.0) or
    # `public const VERSION = '5.1.0';` (Matomo 5.1+). Pre-releases append a suffix
    # (`2.0-a1`, `1.12-b9`, `5.1.0-rc1`, `5.1.0-b3.20240515080303`,
    # `5.12.0-alpha.20260607014952`), which is part of the captured token. Anchoring
    # on `const VERSION` keeps other string constants ending in "N = '" from
    # matching.
    # Verified against Piwik/Matomo 0.2.10 to 6.0.0-b5, all 1060 tags that ship
    # core/Version.php (github.com/matomo-org/matomo).
    success, matomo_version = lib.disk.grep_file(
        os.path.join(args.PATH, 'core/Version.php'),
        r"\bconst VERSION\s*=\s*'(\d+(?:\.\d+)+[^']*)'",
    )
    if not success:
        return ''
    if matomo_version:
        return matomo_version  # 3.13.4, 5.1.0-rc1
    return ''


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
    installed_version = get_installed_version(args)
    if not installed_version:
        lib.base.cu(
            f'Matomo not found at `{args.PATH}`. '
            'Use --path to point at the installation directory.'
        )

    # init some vars
    perfdata = ''
    # lib.version reads a suffix as version parts (4.5rc1 -> 4.51), use the core
    installed_core = re.match(r'\d+(?:\.\d+)*', installed_version).group()

    # analyze data
    state, eol = lib.version.check_eol(
        'https://endoflife.date/api/matomo.json',
        installed_core,
        offset_eol=args.OFFSET_EOL,
        check_major=args.CHECK_MAJOR,
        check_minor=args.CHECK_MINOR,
        check_patch=args.CHECK_PATCH,
        insecure=args.INSECURE,
        no_proxy=args.NO_PROXY,
        proxy=args.PROXY,
        timeout=args.TIMEOUT,
        unreachable_severity=args.UNREACHABLE_SEVERITY,
    )

    # build the message
    msg = f'Matomo v{installed_version} ({eol})'

    perfdata += lib.base.get_perfdata(
        'matomo-version',
        lib.version.version2float(installed_core),
        uom=None,
        _min=0,
    )

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


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