#!/usr/bin/python3 -d
"""
This file is part of Linspector (https://linspector.org/)
Copyright (c) 2022 Johannes Findeisen <you@hanez.org>. All Rights Reserved.
See LICENSE (MIT license).
"""
# TODO: VERY IMPORTANT! IMPLEMENT ERROR HANDLING ALL THE WAY...!!!
#  Only exit execution on critical core errors. Do not exit when monitors are failing on
#  configuration and execution, but log these errors.
import argparse
import signal
import sys

from loguru import logger as log

from linspector.configuration import Configuration
from linspector.environment import Environment
from linspector.linspector import Linspector
from linspector.monitors import Monitors

__version__ = '0.21.4'
__author__ = 'Johannes Findeisen <you@hanez.org>'


def parse_args():
    parser = argparse.ArgumentParser(
        description='linspector is a infrastructure and system monitoring daemon and toolchain.',
        epilog='author: ' + __author__,
        prog='linspector')

    parser.add_argument('configuration_path', metavar='CONFIGURATION_PATH',
                        help='the configuration path to use')

    parser.add_argument('-d', '--daemon', default=False, dest='daemon', action='store_true',
                        help='run linspector as native daemon (default: false)')

    parser.add_argument('-k', '--kill', default=False, dest='kill', action='store_true',
                        help='kill the daemon if it is running (default: false)')

    parser.add_argument('-r', '--restart', default=False, dest='restart', action='store_true',
                        help='restart the daemon if it is running (default: false)')

    parser.add_argument('-v', '--version', action='version', version='%(prog)s ' + str(__version__))

    return parser.parse_args()


def linspector():
    args = parse_args()
    monitors = None
    notifications = {}
    plugins = {}
    # the scheduler is a dict to make it possible in the future to run more than one scheduler in
    # one linspector instance. need to think about it a little more...
    scheduler = {}
    services = {}
    tasks = {}

    log.remove()
    default_log_format = '[{time:YYYY-MM-DD HH:mm:ss.SSSSSS ZZ}] [{elapsed}] [{level}] [linspector] ' \
                         '[{name}:{function}:{line}]: {message}'
    log_level = "INFO"
    log.add(sys.stderr, backtrace=True, colorize=True, diagnose=True, format=default_log_format, level=log_level)

    try:
        configuration = Configuration(args.configuration_path, log)
    except Exception as err:
        log.error('configuration error: {0}'.format(err))
        sys.exit(1)

    if configuration.get_option('linspector', 'log_level'):
        log.remove()
        log_format = default_log_format
        if configuration.get_option('linspector', 'log_format'):
            log_format = configuration.get_option('linspector', 'log_format')

        if configuration.get_option('linspector', 'log_level'):
            log_level = configuration.get_option('linspector', 'log_level')

        log.add(sys.stderr, backtrace=True, colorize=True, diagnose=True, format=log_format, level=log_level)

    if configuration.get_option('linspector', 'logfile'):
        logfile_count = '10'
        if configuration.get_option('linspector', 'logfile_count'):
            logfile_count = configuration.get_option('linspector', 'logfile_count')

        logfile_format = default_log_format
        if configuration.get_option('linspector', 'logfile_format'):
            logfile_format = configuration.get_option('linspector', 'logfile_format')

        logfile_level = log_level
        if configuration.get_option('linspector', 'logfile_level'):
            logfile_level = configuration.get_option('linspector', 'logfile_level')

        logfile_size = '1MB'
        if configuration.get_option('linspector', 'logfile_size'):
            logfile_size = configuration.get_option('linspector', 'logfile_size')

        log.add(configuration.get_option('linspector', 'logfile'), backtrace=True, diagnose=True, enqueue=True,
                format=logfile_format, level=logfile_level, retention=int(logfile_count), rotation=logfile_size)

    environment = Environment(log)

    try:
        monitors = Monitors(configuration, environment, log, notifications, services, tasks)
    except Exception as err:
        log.warning('monitor initialization error: {0}'.format(err))

    try:
        linspector = Linspector(configuration, environment, log, monitors, plugins, scheduler)
        # linspector.print_debug()
    except Exception as err:
        log.critical('core initialization error: {0}'.format(err))
        log.critical('program terminating...')
        sys.exit(1)

    # daemon initialization
    if args.daemon:
        try:
            from linspector.linspectord import Linspectord
            linspectord = Linspectord(configuration, environment, linspector, log)
            # do handling of restart, start and stop commands but for now "start" is enough... ;)
            if args.kill:
                log.info('stopping daemon.')
                linspectord.stop()
            elif args.restart:
                log.info('restarting daemon.')
                linspectord.restart()
            else:
                log.info('starting daemon.')
                linspectord.start()
        except Exception as err:
            log.critical('daemon error: {0}'.format(err))
            sys.exit(1)
    else:
        try:
            signal.pause()
        except KeyboardInterrupt:
            log.info('program terminated by user!')


if __name__ == '__main__':
    linspector()
