# -*- encoding: utf-8 -*-
"""
KERIA
keria.app.indirecting module

simple indirect mode demo support classes
"""
import falcon
from keri.app import httping
from keri.core import eventing
from keri.core.coring import Ilks, Sadder
from keri.kering import Protocols, Kinds

CESR_DESTINATION_HEADER = "CESR-DESTINATION"


class HttpEnd:
    """
    HTTP handler that accepts and KERI events POSTed as the body of a request with all attachments to
    the message as a CESR attachment HTTP header.  KEL Messages are processed and added to the database
    of the provided Habitat.

    This also handles `req`, `exn` and `tel` messages that respond with a KEL replay.
    """

    TimeoutQNF = 30
    TimeoutMBX = 5

    def __init__(self, agency):
        """
        Create the KEL HTTP server from the Habitat with an optional Falcon App to
        register the routes with.

        Parameters
             agency (Agency): the agency from which to load the Agent for each request

        """
        self.agency = agency

    def on_post(self, req, rep):
        """
        Handles POST for KERI event messages.

        Parameters:
              req (Request) Falcon HTTP request
              rep (Response) Falcon HTTP response

        ---
        summary:  Accept KERI events with attachment headers and parse
        description:  Accept KERI events with attachment headers and parse.
        tags:
           - Events
        requestBody:
           required: true
           content:
             application/json:
               schema:
                 type: object
                 description: KERI event message
        responses:
           204:
              description: KEL EXN, QRY, RPY event accepted.

        """
        if req.method == "OPTIONS":
            rep.status = falcon.HTTP_200
            return

        if CESR_DESTINATION_HEADER not in req.headers:
            raise falcon.HTTPBadRequest(title="CESR request destination header missing")

        aid = req.headers[CESR_DESTINATION_HEADER]
        agent = self.agency.lookup(aid)
        if agent is None:
            raise falcon.HTTPNotFound(title=f"unknown destination AID {aid}")

        rep.set_header('Cache-Control', "no-cache")
        rep.set_header('connection', "close")

        cr = httping.parseCesrHttpRequest(req=req)
        serder = Sadder(ked=cr.payload, kind=Kinds.json)
        msg = bytearray(serder.raw)
        msg.extend(cr.attachments.encode("utf-8"))

        agent.parser.ims.extend(msg)

        if serder.proto == Protocols.acdc:
            rep.status = falcon.HTTP_204

        else:
            ilk = serder.ked["t"]
            if ilk in (Ilks.icp, Ilks.rot, Ilks.ixn, Ilks.dip, Ilks.drt, Ilks.exn, Ilks.rpy):
                rep.status = falcon.HTTP_204
            elif ilk in (Ilks.vcp, Ilks.vrt, Ilks.iss, Ilks.rev, Ilks.bis, Ilks.brv):
                rep.status = falcon.HTTP_204
            elif ilk in (Ilks.qry,):
                if serder.ked["r"] in ("mbx",):
                    raise falcon.HTTPNotFound(title="no mailbox support in KERIA")
                else:
                    rep.status = falcon.HTTP_204

    def on_put(self, req, rep):
        """
        Handles PUT for KERI mbx event messages.

        Parameters:
              req (Request) Falcon HTTP request
              rep (Response) Falcon HTTP response

        ---
        summary:  Accept KERI events with attachment headers and parse
        description:  Accept KERI events with attachment headers and parse.
        tags:
           - Events
        requestBody:
           required: true
           content:
             application/json:
               schema:
                 type: object
                 description: KERI event message
        responses:
           200:
              description: Mailbox query response for server sent events
           204:
              description: KEL or EXN event accepted.
        """
        if req.method == "OPTIONS":
            rep.status = falcon.HTTP_200
            return

        if CESR_DESTINATION_HEADER not in req.headers:
            raise falcon.HTTPBadRequest(title="CESR request destination header missing")

        aid = req.headers[CESR_DESTINATION_HEADER]
        agent = self.agency.lookup(aid)
        if agent is None:
            raise falcon.HTTPNotFound(title=f"unknown destination AID {aid}")

        rep.set_header('Cache-Control', "no-cache")
        rep.set_header('connection', "close")

        agent.parser.ims.extend(req.bounded_stream.read())

        rep.status = falcon.HTTP_204


def loadEnds(app, agency):
    """ Add Falcon HTTP server endpoints for the HTTP endpoint class HttpEnd """
    httpEnd = HttpEnd(agency=agency)
    app.add_route("/", httpEnd)
