"""
The Nano E2E Server Protocol - Nano side

Describes messages arriving from the server and what responses should look like. These messages hold the E2E secured
messages as their payloads. Additional fields (metadata) control cache-usage cryptography key-lookup and error
indications.

Cryptographic authenticity of the requesting party must be (and will be) ensured for all requests:
    - Any party can ECDH-HKDF encrypt a request which ultimately reveals their identity (or the lack thereof)
        - The public keys of the requester has to be available by an account_id lookup or as metadata
        - The account_id can be checked for access by policies
        - The policies shall be selected by the request target resource_id (for groups) for example
        - Group policies stored by the server form a blockchain which cannot be falsified or forged

Request fields and their properties:
    - payload: (encrypted by requesting party)
        - type
            -> designates the requested operation (handler)
        ? resource_id
            -> relevant to for anyone other than the owner to select policies by
            -> lying about this will not yield successful results as the nano has strict explicit-allow only policies
        ? handler-specific-fields
    - account_id
        -> server supplies it for payload key lookup only
        -> server manipulation is not possible as long as the nano checks the keys & trust fingerprints
    - ephemeral_public_key
        -> requesting party's for ECDH secret derivation and decryption
        -> the nano must only use this when the account_id is 0 and treat the requesting party as anonymous
    - cache_key/transfer_key/part
        -> server manages it with the client to control data transfer and caching
        -> server manipulation may only disrupt service (both client parties can check authenticity with crypto)

Response fields and their properties:
    - payload: (encrypted by nano-server-worker)
        -> encryption will be chosen according to part and cache-usage
        ? handler-specific-fields
    - cache_key/transfer_key/count
        -> for initiating requests (part is null)
    - error
        -> payload is ignored by the server if an error code is present

Request lifetime paths:

1. Nano receives initial request
    The initial request probes the Nano if it wants to execute the request at all, or if the response can be
    retrieved from cache.
    The client must *not* supply any cache_key, transfer_key or part. Omitting those fields indicates that the
    request is an initial one.

    The handler may respond with:
        - low level error
            - error field is a number
        - target data is accessible, setup transfer
            - payload
                - fingerprint binding of the request to the cache/transfer_key for authenticity
                -> always p2p encrypted
            - count
            - not cacheable (cache_key is None, transfer_key is not None)
            - cacheable (cache_key is not None, transfer_key is None)

2. Nano receives part request (multiple depending on response chunking)
    Responses to requests are chunked into max 1MB parts, all of which must be individually requested by a logic
    for the client. (server helps to automate this)

    The handler may respond with:
        - low level error
            - error field is a number
            -> target data is permanently no longer available for example
            -> target data has changed and must be re-requested aka conflict
            -> caching state is not satisfiable (cache_key/transfer_key became invalid, could be similar to conflict)
            -> payload is ignored and should be omitted
        - data is available as the request's part and cache_key or transfer_key indicates
            - error field must be omitted
            - payload is encrypted for p2p or group depending on *_key

Handler states
The handlers should avoid stateful constructs wherever possible. If they require static state for their
functionality then those shall be put and encrypted into the cache_key or the transfer_key respectively.
Changing/advancing states if absolutely necessary must be made in a way that any worker can access them
for work and race conditions are handled even for parallel requests.

Handlers that receive multipart input
Query- and command-like requests will always be single part. The only expected handlers that will receive more
than a single part of data are upload handlers. These will need to collect the incoming data and track them. If
some does not arrive within a reasonable time, they must be discarded.

Requests are preprocessed at the gateway and servers work with the preprocessed requests. See NanoRequestContext
and NanoRequestPayload.
"""


class NanoServerRequest(object):
    """
    Fields of the request that arrives from the server.
    """

    ACCOUNT_ID = "a"
    EPHEMERAL_PUBLIC_KEY = "e"  # when account_id is 0 (anonymous request)
    ROOM_ID = "R"  # none for direct request; must match with the one in the base-request; see that for more info
    CACHE_KEY = "c"
    TRANSFER_KEY = "t"
    PAYLOAD = "P"
    PART = "p"
    REMOTE_IP = "r"  # Optional[Union[str, bytes]]; ip address of the client, reported by the server


class NanoServerResponse(object):
    """
    Possible fields of the response that we send to the server.
    """

    CACHE_KEY = "c"
    TRANSFER_KEY = "t"
    COUNT = "n"
    PAYLOAD = "p"
    ERROR = "e"
    LATENCY = "l"  # internal latency of processing the request
