#!/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
from email.utils import make_msgid
from socket import gethostname

import lib.args
import lib.base
import lib.icinga
import lib.mail
from lib.globals import STATE_UNKNOWN

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

DESCRIPTION = """Sends notifications for hosts using mail."""

TIMEOUT = 8  # seconds
DEFAULT_MAIL_ENCRYPTION = 'none'
DEFAULT_MAIL_PORT = 25
DEFAULT_MAIL_SERVER = 'localhost'


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

    parser.add_argument(
        '-V',
        '--version',
        action='version',
        version=f'%(prog)s: v{__version__} by {__author__}',
    )

    parser.add_argument(
        '--datetime',
        help=lib.args.help('--datetime'),
        dest='DATETIME',
        required=True,
    )

    parser.add_argument(
        '--host-address',
        help=lib.args.help('--host-address'),
        dest='HOST_ADDRESS',
    )

    parser.add_argument(
        '--host-displayname',
        help=lib.args.help('--host-displayname'),
        dest='HOST_DISPLAYNAME',
        required=True,
    )

    parser.add_argument(
        '--host-output',
        help=lib.args.help('--host-output'),
        dest='HOST_OUTPUT',
    )

    parser.add_argument(
        '--host-state',
        help=lib.args.help('--host-state'),
        dest='HOST_STATE',
        required=True,
    )

    parser.add_argument(
        '--hostname',
        help='Set the hostname ($host.name$).',
        dest='HOSTNAME',
    )

    parser.add_argument(
        '--icingaweb2-url',
        help=lib.args.help('--icingaweb2-url'),
        dest='ICINGAWEB2_URL',
    )

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

    parser.add_argument(
        '--mail-encryption',
        help=lib.args.help('--mail-encryption') + ' Default: %(default)s.',
        dest='MAIL_ENCRYPTION',
        choices=['none', 'starttls', 'tls'],
        default=DEFAULT_MAIL_ENCRYPTION,
    )

    parser.add_argument(
        '--mail-password',
        help=lib.args.help('--mail-password'),
        dest='MAIL_PASSWORD',
    )

    parser.add_argument(
        '--mail-port',
        help=lib.args.help('--mail-port') + ' Default: %(default)s.',
        dest='MAIL_PORT',
        type=int,
        default=DEFAULT_MAIL_PORT,
    )

    parser.add_argument(
        '--mail-recipient',
        help=lib.args.help('--mail-recipient'),
        dest='MAIL_RECIPIENT',
        required=True,
    )

    parser.add_argument(
        '--mail-sender',
        help=lib.args.help('--mail-sender'),
        dest='MAIL_SENDER',
        required=True,
    )

    parser.add_argument(
        '--mail-server',
        help=lib.args.help('--mail-server') + ' Default: %(default)s.',
        dest='MAIL_SERVER',
        default=DEFAULT_MAIL_SERVER,
    )

    parser.add_argument(
        '--mail-user',
        help=lib.args.help('--mail-user'),
        dest='MAIL_USER',
    )

    parser.add_argument(
        '--notes',
        help=lib.args.help('--notes'),
        dest='NOTES',
    )

    parser.add_argument(
        '--notes-url',
        help=lib.args.help('--notes-url'),
        dest='NOTES_URL',
    )

    parser.add_argument(
        '--notification-author',
        help=lib.args.help('--notification-author'),
        dest='NOTIFICATION_AUTHOR',
    )

    parser.add_argument(
        '--notification-comment',
        help=lib.args.help('--notification-comment'),
        dest='NOTIFICATION_COMMENT',
    )

    parser.add_argument(
        '--notification-type',
        help=lib.args.help('--notification-type'),
        dest='NOTIFICATION_TYPE',
    )

    parser.add_argument(
        '--perfdata',
        help=lib.args.help('--perfdata'),
        dest='PERFDATA',
    )

    parser.add_argument(
        '--short',
        help=lib.args.help('--short'),
        dest='SHORT',
        action='store_true',
        default=False,
    )

    args, _ = parser.parse_known_args()
    return args


def generate_mail_content(args, logo_cid):
    """Build the plain-text and HTML representation of the notification mail."""
    colors = {
        'ACKNOWLEDGEMENT': '#FFFF80',
        'CRITICAL': '#FFAA60',
        'DOWN': '#FFAA60',
        'DOWNTIMECANCELLED': '#FFFF80',
        'DOWNTIMEEND': '#80FF80',
        'DOWNTIMESTART': '#80FFFF',
        'FLAPPINGDISABLED': '#FFFF80',
        'FLAPPINGSTART': '#FF8080',
        'FLAPPINGSTOP': '#80FF80',
        'OK': '#80FF80',
        'PROBLEM': '#FF8080',
        'RECOVERY': '#80FF80',
        'TEST': '#80FFFF',
        'UNKNOWN': '#80FFFF',
        'UNREACHABLE': '#80FFFF',
        'UP': '#80FF80',
        'WARNING': '#FFFF80',
    }

    rows = []

    if args.NOTIFICATION_TYPE:
        rows += [
            {
                'left_column': 'Notification Type:',
                'right_column': args.NOTIFICATION_TYPE,
                'right_column_attributes': f'style="background-color: {colors.get(args.NOTIFICATION_TYPE)}"',
            },
        ]

    rows += [
        {
            'left_column': 'Host:',
            'right_column': args.HOST_DISPLAYNAME,
        }
    ]

    rows += [
        {
            'left_column': 'Host State:',
            'right_column': args.HOST_STATE,
            'right_column_attributes': f'style="background-color: {colors.get(args.HOST_STATE)}"',
        },
    ]

    if args.HOST_OUTPUT:
        rows += [
            {
                'left_column': 'Host Output:',
                'right_column': args.HOST_OUTPUT,
            },
        ]

    if args.HOSTNAME:
        rows += [
            {
                'left_column': 'Hostname:',
                'right_column': args.HOSTNAME,
            },
        ]

    if args.HOST_ADDRESS:
        rows += [
            {
                'left_column': 'IP Address:',
                'right_column': args.HOST_ADDRESS,
            },
        ]

    rows += [
        {
            'left_column': 'Event Time:',
            'right_column': args.DATETIME,
        },
    ]

    if args.PERFDATA:
        rows += [
            {
                'left_column': 'Perfdata:',
                'right_column': args.PERFDATA,
            },
        ]

    if args.NOTIFICATION_COMMENT:
        rows += [
            {
                'left_column': 'Author:',
                'right_column': args.NOTIFICATION_AUTHOR,
            },
            {
                'left_column': 'Comment:',
                'right_column': args.NOTIFICATION_COMMENT,
            },
        ]

    web_url = lib.icinga.build_icingaweb2_url(args.ICINGAWEB2_URL, args.HOSTNAME)
    if web_url:
        rows += [
            {
                'left_column': 'IcingaWeb2 URL:',
                'right_column': web_url,
            },
        ]

    if args.NOTES:
        rows += [
            {
                'left_column': 'Notes:',
                'right_column': args.NOTES,
            },
        ]

    if args.NOTES_URL:
        rows += [
            {
                'left_column': 'Notes URL:',
                'right_column': args.NOTES_URL,
            },
        ]

    return lib.icinga.render_notification_mail(rows, logo_cid, gethostname())


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)

    # build the message
    subject = ''
    html = ''
    images = None

    if args.SHORT:
        plain = f'{args.HOST_STATE:.4}: {args.HOST_DISPLAYNAME} ({args.DATETIME})'

        if args.NOTIFICATION_COMMENT:
            plain += (
                f'\nCOMMENT: {args.NOTIFICATION_COMMENT} ({args.NOTIFICATION_AUTHOR})'
            )
    else:
        # Pin the domain to the short hostname so make_msgid() does not
        # fall back to socket.getfqdn(). On hosts with a long FQDN the
        # resulting Content-ID header overflows 80 characters and gets
        # wrapped by Python's quoted-printable encoder, which breaks the
        # cid:<...> reference in the HTML body and turns the inline logo
        # into an attachment (see python/cpython#100293 and issue #790).
        logo_cid = make_msgid(domain=gethostname())
        plain, html = generate_mail_content(args, logo_cid)

        subject = f'Host "{args.HOST_DISPLAYNAME}" is {args.HOST_STATE}'
        if args.NOTIFICATION_TYPE:
            subject = f'[{args.NOTIFICATION_TYPE}] {subject}'

        images = [
            {
                'data': lib.icinga.get_logo(),
                'maintype': 'icinga',
                'subtype': 'png',
                'cid': logo_cid,
            }
        ]

    # over and out
    lib.base.coe(
        lib.mail.send(
            args.MAIL_SERVER,
            args.MAIL_SENDER,
            args.MAIL_RECIPIENT,
            encryption=args.MAIL_ENCRYPTION,
            html=html,
            images=images,
            insecure=args.INSECURE,
            password=args.MAIL_PASSWORD,
            plain=plain,
            port=args.MAIL_PORT,
            subject=subject,
            timeout=TIMEOUT,
            username=args.MAIL_USER,
        )
    )


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