"""
Name-value-pair (NVP) JSON representor. It just serializes a run-time WeSTL document's data section verbatim.
"""

import json
from heaobject.root import json_encode
from .error import ParseException
from .representor import Representor
from jsonschema import validate, ValidationError
from aiohttp.web import Request
from typing import Mapping, Any, Union, Dict, List
from yarl import URL
from itertools import chain


MIME_TYPE = 'application/json'

NVPJSON_SCHEMA = {
    'type': 'object'
}


class NVPJSON(Representor):
    MIME_TYPE = MIME_TYPE

    async def formats(self, request: Request, wstl_obj: Union[List[Dict[str, Any]], Dict[str, Any]], dumps=json.dumps) -> bytes:
        """
        Formats a run-time WeSTL document as a list of name-value pair JSON documents.

        :param request: the HTTP request.
        :param wstl_obj: dict with run-time WeSTL JSON, or a list of run-time WeSTL JSON dicts.
        :param dumps: any callable that accepts dict with JSON and outputs str. Cannot be None.
        :return: JSON string.
        """
        if not isinstance(wstl_obj, list):
            wstl_obj_ = wstl_obj['wstl'].get('data', [])
        else:
            wstl_obj_ = list(chain.from_iterable(w['wstl'].get('data', []) for w in wstl_obj))
        return dumps(wstl_obj_, default=json_encode).encode('utf-8')

    async def parse(self, request: Request) -> Mapping[str, Any]:
        """
        Parses the body of an HTTP request containing a JSON document into a dict-like object.

        :param request: the HTTP request. Cannot be None.
        :return: the data section of the JSON document transformed into a dict-like object.
        """
        result = await request.json()
        try:
            validate(result, NVPJSON_SCHEMA)
            return result
        except ValidationError as e:
            raise ParseException from e


