"""A module of JSON API utilities."""


def is_valid_resource_representation(resource, create=False):
    """
    Checks if resource is a valid *resource object* or *resource identifier*.

    Only checks the member properties, **not** the values assigned to
    the properties.

    Args:
        resource: The resource object checked
        create: If set to ``True``, denotes the resource is part of a
            create operation, which means the ``id`` members is not required
            as it may be generated by the server.

    Returns
        bool: ``True`` if it follows the JSON API resource format.
            ``False`` otherwise.
    """
    if create:
        return True if 'type' in resource else False
    else:
        members = ('id', 'type')
        for member in members:
            if member not in resource:
                return False
        return True


def is_valid_primary_data(primary_data, collection=False):
    """
    Checks candidate primary data for valid structure.

    Args:
        primary_data: Candidate data
        collection (bool): Whether the primary data is supposed to be
            a single resource or a collection of resources

    Returns:
        bool: ``True`` if it meets JSON API primary data requirements.
            ``False`` otherwise.
    """
    if collection:
        if isinstance(primary_data, list):
            if len(primary_data) == 0:
                return True
            else:
                for resource in primary_data:
                    if not is_valid_resource_representation(resource):
                        return False
                return True
    else:
        if isinstance(primary_data, dict):
            return is_valid_resource_representation(primary_data)
        if primary_data is None:
            return True
    return False


def is_valid_top_level(document, collection=False):
    """
    Checks candidate JSON API document for valid top-level
    structure.

    Args:
        document: A candidate JSON API document
        collection (bool): Whether the primary data is supposed to be
            a single resource or a collection of resources

    Raises:
        TypeError: If document is not an iterable.

    Returns:
        bool: ``True`` if it meets JSON API top-level specification.
            ``False`` otherwise.

    """
    try:
        if 'data' in document and 'errors' in document:
            return False
        if 'included' in document and 'data' not in document:
            return False
        if 'data' in document:
            primary_data_validation = is_valid_primary_data(document['data'], collection)
            if 'included' in document and not isinstance(document['included'], list):
                return False
            return primary_data_validation
        if 'errors' in document:
            return True if isinstance(document['errors'], list) else False
        if 'meta' in document:
            return True if isinstance(document['meta'], dict) else False
        return False
    except TypeError:
        return False
