#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import logging
import signal
import os

from flamingo.server.logging import RPCHandler

rpc_logging_handler = RPCHandler(level=logging.DEBUG)

logging.basicConfig(level=logging.DEBUG)
logging.root.handlers = [rpc_logging_handler]

# setup server
import asyncio  # NOQA

from aiohttp.web import Application, run_app  # NOQA

from flamingo.core.utils.cli import gen_default_parser, parse_args, error  # NOQA
from flamingo.server.server import Server  # NOQA

# parse command line
parser = gen_default_parser(prog='flamingo server')

parser.add_argument('--port', type=int, default=8080)
parser.add_argument('--host', type=str, default='localhost')
parser.add_argument('--disable-overlay', action='store_true')
parser.add_argument('--enable-browser-caching', action='store_true')
parser.add_argument('--refresh-interval', type=float, default=0.25)
parser.add_argument('--threads', type=int, default=6)
parser.add_argument('--log-backlog', type=int, default=2500)
parser.add_argument('--shell', action='store_true')
parser.add_argument('--shell-history', action='store_true')

namespace, settings = parse_args(parser, setup_logging=False)

if namespace.threads < 4:
    exit(error('at least 4 threads are required to run properly'))

log_level = {
    'DEBUG': logging.DEBUG,
    'INFO': logging.INFO,
    'WARN': logging.WARN,
    'ERROR': logging.ERROR,
    'FATAL': logging.FATAL,
}[namespace.log_level]

rpc_logging_handler.internal_level = log_level
rpc_logging_handler.buffer_max_size = namespace.log_backlog
rpc_logging_handler.loggers = namespace.loggers

# setup aiohttp app
loop = asyncio.get_event_loop()
app = Application(loop=loop)

# setup flamingo server
try:
    server = Server(
        app=app,
        loop=loop,
        rpc_max_workers=namespace.threads,
        settings=namespace.settings or [],
        disable_overlay=namespace.disable_overlay,
        enable_browser_caching=namespace.enable_browser_caching,
        watcher_interval=namespace.refresh_interval,
        rpc_logging_handler=rpc_logging_handler,
    )

except KeyboardInterrupt:
    exit()

# setup shell
if namespace.shell:
    async def start_shell(server):
        def _start_shell(server):
            server.start_shell(history=namespace.shell_history)
            os.kill(os.getpid(), signal.SIGTERM)

        await server.await_unlock()
        await server.rpc.worker_pool.run(_start_shell, server)

        print('shell stopped')

    loop.create_task(start_shell(server))

# run
print('starting server on http://localhost:{}/'.format(namespace.port))

try:
    # this is a hack that is necessary because of the current design of the
    # rpc worker_pool
    loop.close = lambda *args, **kwargs: None

    run_app(app=app, host=namespace.host, port=namespace.port,
            print=lambda *args, **kwargs: None)

except OSError:
    server.shutdown()
    exit(error('ERROR: can not bind to port {}'.format(namespace.port)))

print('\rshutting down server')
server.shutdown()
