#!python
import argparse
import json
import logging
import os
import signal
import socket
import sys

from uun_iot import Gateway
from uun_iot.utils import LoggingSystemdHandler
from uun_livecam.modules import init

logging.getLogger().handlers = []  # onvif inserts root handlers

__version__ = "0.6.0"
__package__ = "uun_livecam"
library = "uun_iot"


def main():
    argp = argparse.ArgumentParser(
        prog=__package__,
        description=(
            "Connect to ONVIF IP camera(s), drive it to desired destinations and take"
            " snapshots."
        ),
    )
    argp.add_argument(
        "action",
        nargs="*",
        help=(
            "possible actions: `reboot ID`: reboots the camera with identifier `ID` (as"
            " specified in JSON configuration)"
        ),
        default=None,
    )
    argp.add_argument(
        "-v", "--version", action="version", version="%(prog) " + __version__
    )
    argp.add_argument(
        "-l",
        "--log",
        metavar="loglevel",
        dest="loglevel",
        type=str,
        help="level of logging: [DEBUG, INFO, WARNING, ERROR, CRITICAL]",
        default="WARNING",
    )
    argp.add_argument(
        "-c",
        "--config",
        metavar="configfile",
        dest="config",
        type=str,
        help="config file location, defaults to 'config.json'",
        default="config.json",
    )
    argp.add_argument(
        "--systemd",
        help="enable output in systemd-friendly format",
        action="store_true",
    )

    args = argp.parse_args()

    if not os.path.exists(args.config):
        sys.exit(f"Could not find configuration file '{args.config}'")

    if len(args.action) not in (0, 2):
        sys.exit("Specify action with 2 arguments or do not specify it at all.")

    if len(args.action) == 2:
        action_name, cam_id = args.action
        if action_name != "reboot":
            sys.exit("Invalid action name '{action_name}'.")
        try:
            socket_path = json.load(open(args.config))["gateway"]["socket"]["path"]
            with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s:
                s.connect(socket_path)
                with s.makefile("rw", encoding="utf-8") as sfile:
                    sfile.write(f"reboot {cam_id}\n")
                    sfile.flush()
                    line = sfile.readline()
                    if line[0] == "0":
                        print(line[1:])
                        sys.exit()
                    else:
                        sys.exit("Got this server socket error: " + line)
        except KeyError:
            sys.exit("Socket path was not specified in config.")

    loglevel = args.loglevel
    llevel = getattr(logging, loglevel.upper(), None)
    if not isinstance(llevel, int):
        sys.exit(f"Invalid log level: {loglevel}")

    loggerw = logging.getLogger(__package__)  # application specific logger
    loggeru = logging.getLogger(library)  # library logger
    loggerw.setLevel(llevel)
    loggeru.setLevel(llevel)
    handler = LoggingSystemdHandler() if args.systemd else logging.StreamHandler()
    handler.setFormatter(logging.Formatter("%(name)s - %(levelname)s - %(message)s"))
    loggerw.addHandler(handler)
    loggeru.addHandler(handler)

    sys.excepthook = lambda exctype, value, tb: logging.getLogger(
        __package__
    ).exception("Exception: ", exc_info=(exctype, value, tb))
    # catch also threading Exceptions for Python 3.8+
    # threading.excepthook = lambda exctype, value, tb: logging.getLogger(
    #    __package__
    # ).exception("Thread Exception: ", exc_info=(exctype, value, tb))

    # start module system
    print(f"===  {__package__}, v{__version__} ===")
    with Gateway(args.config, init) as g:
        # Register a SIGTERM signal, as it is issued by systemd on stop/restart.
        #   Because by default, it does not run destructors.
        # Ctrl-C (SINGINT) correctly runs destructors, so no need to register.
        # SIGUSR1 is used internally by HealthCheck to restart the gateway
        signal.signal(signal.SIGTERM, g.signal_handler)
        signal.signal(signal.SIGINT, g.signal_handler)
        signal.signal(signal.SIGUSR1, g.signal_handler)

        g.stopev.wait()


if __name__ == "__main__":
    main()
