import logging
import logging.handlers
import os
import sys

sys.path.insert(0, './modules/libs.zip')
sys.path.insert(0, './modules')
sys.path.insert(0, './')

from multiprocessing import Process

import json
import requestlogger


class AccessLoggerMiddleware:
    def __init__(self, app, log_path):
        self.app = app

        self.logger = logging.getLogger('accesslogger')
        self.logger.setLevel(logging.DEBUG)
        formatter1 = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s: %(message)s')
        file_handler1 = logging.FileHandler(log_path)
        file_handler1.setLevel(logging.DEBUG)
        file_handler1.setFormatter(formatter1)
        self.logger.addHandler(file_handler1)

    def __call__(self, environ, start_response):
        def _start_response(status, headers, *args):
            self.logger.info(f'{environ["REMOTE_ADDR"]} {environ["REQUEST_METHOD"]} {environ["PATH_INFO"]}')
            return start_response(status, headers, *args)

        return self.app(environ, _start_response)


def start_server(port):
    """
        Starting WSGIServer instance for desired port as
        separate python process
    """
    from api_ws import myapp, app
    import wsgiserver

    pth = app.config["CONF"]["logging_web"]
    app.config["port"] = str(port)

    if app.config["CONF"].get("log_http_access", None) in ("D", "d"):
        myapp = AccessLoggerMiddleware(myapp, f'{pth}\\{port}access_http.log')
    d = wsgiserver.WSGIPathInfoDispatcher(
        {'/': _with_access_log(myapp, f'{pth}\\{port}access.log')}
    )
    server = wsgiserver.WSGIServer(
        d, 
        host = '0.0.0.0', 
        port = port, 
        timeout = app.config["CONF"]["timeout"], 
        accepted_queue_timeout = app.config["CONF"]["timeout"]*2, 
        request_queue_size = 200,
        numthreads = app.config["CONF"]["number_of_requests"],
        certfile = app.config["CONF"].get("cert_file", ""),
        keyfile = app.config["CONF"].get("key_file", ""),
        ca_certs=None,
    )
    try:
        server.start()
    except KeyboardInterrupt:
        server.stop()


def _with_access_log(app, filepath = None, when = 'd', interval = 7, **kwargs):
    """
        Time rotating logs for InfoWS web server as Apache standard format
    """
    if filepath is not None:
        handlers = [
            logging.handlers.TimedRotatingFileHandler(
                filepath, when, interval, **kwargs
            )
        ]
    else:
        handlers = [logging.StreamHandler()]
    return requestlogger.WSGILogger(
        app, handlers, requestlogger.ApacheFormatter()
    )


def read_config_file():
    """
        Reading and return main config of InfoWS
    """
    main_path = os.path.abspath(
        os.path.join(os.path.realpath(__file__), r"..\..")
    )
    config_file = os.path.join(main_path, "config.json")

    with open(config_file, mode = 'r') as conf_file:
        return json.loads(conf_file.read())


if __name__ == '__main__':
    """
        Entry point - read config, launching servers
    """

    os.system("color")
    print("\n\033[94mReading configuration \033[37m... \033[32mDONE")
    _config = read_config_file()
    print("\n\033[37mStarting workers:")
    list_servers = [Process(target = start_server, name=f"InfoWS_Server_{port}", args = (port, ))
                    for port in _config["infows_port"]]
    try:
        for proc in list_servers:
            print("\033[94m{} \033[37m...\033[32m {}\033[0m".format(proc.name, "DONE"))
            proc.start()

        print("\n\033[32mserver started ...\033[0m")
        for proc in list_servers:
            proc.join()
    except KeyboardInterrupt:
        for proc in list_servers:
            proc.terminate()
