""" App """
import asyncio
import logging
import signal
import sys
from asyncio import AbstractEventLoop
from typing import Optional

from absl import app, flags
from absl.flags import FLAGS
from marshmallow import EXCLUDE

from utils.ether_service.entities.data.kr_packet import KrPacketV2
from utils.ether_service.utils.json_func import json_loads
from utils.ws_client import WSClient


logger = logging.getLogger(__name__)


flags.DEFINE_string('station_id', None, "Station_id")
flags.DEFINE_string('file_name', None, "File where to save the history")


def init_logging(filename=None, level=None):
    """ init logging on the app level """
    logging_config = {"format": "%(message)s",
                      "level": level or logging.DEBUG}
    if filename is not None:
        logging_config["filename"] = filename
    logging.getLogger().handlers = []
    logging.basicConfig(**logging_config)


def stop_server(server: WSClient, io_loop: AbstractEventLoop):
    """ Stop server and execute finish gracefully """

    def wr(_signum, _frame):
        """ We need a wraper to dynamicaly set server """
        server.stop()
        io_loop.stop()

    return wr


# noinspection PyShadowingNames
def try_to_log(kr_packet: KrPacketV2,
               log_name: Optional[str] = None) -> None:
    """ try to save log into the file """
    if log_name is not None:
        try:
            with open(log_name, "a") as f:
                f.write(f"{kr_packet}\r\n")
        except IOError:
            logging.error("save to file error!", exc_info=sys.exc_info())


def handle_message(data: bytes) -> None:
        """ Handle Message """
        message = json_loads(data)
        if message is None:
            logger.warning(f"Failed to parse message!")
            logger.debug(f"Failed to parse message!: {repr(data)}")
            return
        # noinspection PyBroadException
        try:
            kr_packet = KrPacketV2.load(message, unknown=EXCLUDE)
            station_id = FLAGS.station_id
            if station_id is None or \
                    station_id.lower() == kr_packet.station_id.lower():
                logging.info(f"{kr_packet}")
                try_to_log(kr_packet)
        except Exception:
            logging.error("handle_message: Error!", exc_info=sys.exc_info())


# noinspection PyShadowingNames
def main(argv) -> None:
    """ Main """

    logging.getLogger("geventwebsocket").level = logging.WARNING
    logging.getLogger("asyncio").level = logging.INFO
    logging_level = logging.INFO
    init_logging(level=logging_level)

    io_loop = asyncio.get_event_loop()
    ws_client = WSClient(io_loop=io_loop, scheme="https", host="cds.s1z.info",
                         path="/api/v1/ws-agg",
                         user="kraken", password="kraken", ca_file="./ca.pem",
                         on_data_handler=handle_message)
    ws_client.start()
    signal.signal(signal.SIGINT, stop_server(ws_client, io_loop))
    signal.signal(signal.SIGTERM, stop_server(ws_client, io_loop))
    io_loop.run_forever()


if __name__ == "__main__":
    app.run(main)
