import os
import logging
from json import JSONDecodeError

import zmq

import helper

from messagehandlerbuilder import SchedCompMessageHandlerBuilder
from schedcomp import CronTabInteractor, CronTabService, EventDefinition
from timeutil import RealClock, RealSleeper
from zeromqmessagehandler import ZeroMqMessageBus, ZeroMqMessageHandler

COMP_NAME = "SchedComp"
logger = logging.getLogger(COMP_NAME)


def main():
    config_path = './config.json'
    if "CONFIG_PATH" in os.environ:
        config_path = os.environ["CONFIG_PATH"]
    if os.path.isdir(config_path):
        configs_files = []
        default_config = os.environ.get("DEFAULT_CONFIG_FILE", "config.json")
        complete_default_config_path = os.path.join(config_path, default_config)
        configs_files.append(complete_default_config_path)
        for file in os.listdir(config_path):
            complete_config_path = os.path.join(config_path, file)
            if os.path.isfile(complete_config_path) and \
                    file.endswith(".json") and \
                    complete_config_path != complete_default_config_path:
                configs_files.append(complete_config_path)
    else:
        configs_files = config_path.split(",")

    config = helper.read_json_from_file_as_dictionary(configs_files[0])
    if "cronTab" not in config:
        config["cronTab"] = []
    for crontab_file in configs_files[1:]:
        try:
            file_crontab = helper.read_json_from_file_as_dictionary(crontab_file)
            if not isinstance(file_crontab, list):
                raise Exception("The crontab file must be a list of event definitions: {}".format(crontab_file))
        except JSONDecodeError as ex:
            raise Exception("Error parsing config file {}".format(crontab_file)) from ex
        config["cronTab"].extend(file_crontab)

    log_path = config_path
    if "LOG_PATH" in os.environ:
        log_path = os.environ["LOG_PATH"]
    helper.config_logger(log_path, COMP_NAME, add_error_handler=True)

    logger.debug("Configuration file:\n{}".format(config))

    context = zmq.Context()
    message_bus = ZeroMqMessageBus(COMP_NAME, context)
    clock = RealClock()
    sleeper = RealSleeper()
    interactors = []
    for entry in config["cronTab"]:
        definitions = []
        if entry.get("headers") is not None and isinstance(entry.get("headers"), list):
            for headers in entry.get("headers"):
                definitions.append(EventDefinition(entry["subject"],
                                                   entry.get("type"),
                                                   entry.get("data"),
                                                   headers))
        else:
            definitions.append(EventDefinition(entry["subject"],
                                               entry.get("type"),
                                               entry.get("data"),
                                               entry.get("headers")))

        for event_definition in definitions:
            interactors.append(CronTabInteractor(message_bus, entry["expression"], event_definition, clock, sleeper))

    cron_tab_service = CronTabService(interactors)
    cron_tab_service.start()

    message_handler = ZeroMqMessageHandler(context,
                                           COMP_NAME,
                                           message_bus,
                                           SchedCompMessageHandlerBuilder())
    message_handler.handle_messages()


if __name__ == '__main__':
    main()
