# -*- encoding: utf-8 -*-
"""
sally.cli.commands module

"""
import argparse
import logging
import pprint

import falcon
from hio.core import http
from keri import help
from keri.app import directing

from sally import log_name, ogler
from sally.core import handling, httping
from sally.core.monitoring import HealthEnd

logger = ogler.getLogger(log_name)

parser = argparse.ArgumentParser(description='Launch SALLY sample web hook server')
parser.set_defaults(handler=lambda args: launch(args),
                    transferable=True)
parser.add_argument('-p', '--http',
                    action='store',
                    default=9923,
                    help="Port on which to listen for web hook events.  Defaults to 9923")


def launch(args, expire=0.0):
    baseFormatter = logging.Formatter('%(asctime)s [hook] %(levelname)-8s %(message)s')
    baseFormatter.default_msec_format = None
    help.ogler.baseConsoleHandler.setFormatter(baseFormatter)
    help.ogler.level = logging.getLevelName(logging.INFO)
    help.ogler.reopen(name="hook", temp=True, clear=True)

    httpPort = args.http

    app = falcon.App(
        middleware=httping.cors_middleware())
    app.add_route("/", WebhookListener())
    app.add_route("/health", HealthEnd())

    server = http.Server(port=httpPort, app=app)
    httpServerDoer = http.ServerDoer(server=server)

    logger.info(f"Sally Web Hook Sample listening on {httpPort}")
    directing.runController(doers=[httpServerDoer], expire=expire)


class WebhookListener:
    """
    Demonstration endpoint for web hook calls that prints events to stdout and stores a simple presentation cache.
    """
    def __init__(self):
        self.received = dict()

    def on_post(self, req, resp):
        """Receives web hook POST events by printing the credential results to stdout and storing presentations them in memory
        Parameters:
            req: falcon.Request HTTP request
            rep: falcon.Response HTTP response
        """
        logger.info("** HEADERS **")
        logger.info(pprint.pprint(req.headers))
        logger.info("*************")

        logger.info("**** BODY ****")
        body = req.get_media()
        logger.info(pprint.pprint(body))
        logger.info("**************")

        data = body.get("data", {})
        if not data:
            logger.error("No data in body")
            resp.media = {"error": "No data in body"}
            resp.status = falcon.HTTP_400
            return
        type = self._resolve_type(data["schema"])

        holder = data.get("recipient", "")
        presentation = dict(
            credential=data.get("credential", ""),
            type=type,
            issuer=body.get("actor", ""),
            holder=holder,
            LEI=data.get("LEI", ""),
            personLegalName=data.get("personLegalName", ""),
            officialRole=data.get("officialRole", ""),
        )
        self.received[holder] = presentation
        resp.status = falcon.HTTP_202

    def _resolve_type(self, schema_said):
        """Return human friendly name for schema type"""
        match schema_said:
            case handling.QVI_SCHEMA:
                return "QVI"
            case handling.LE_SCHEMA:
                return "LE"
            case handling.OOR_AUTH_SCHEMA:
                return "OOR Auth"
            case handling.OOR_SCHEMA:
                return "OOR"
            case _:
                raise ValueError(f"Unknown schema type with SAID: {schema_said}")

    def on_get(self, req, resp):
        """
        Tells the presenter if they have presented a credential before.
        Used in testing to determine that a presentation has succeeded.
        """
        holder = req.get_param("holder", required=True)
        if holder in self.received:
            resp.media = self.received[holder]
            resp.status = falcon.HTTP_200
        else:
            resp.media = {"error": f"No credential presented by {holder}"}
            resp.status = falcon.HTTP_404

