# (c) cavaliba.com - related.py


from app_data.models import DataEAV
from app_data.schema import Schema


def get_unwanted_schemanames():

    # NEXT : create schema option / configuration
    return ["sirene_message"]


def is_authorized_schema(schemaname=None, aaa=None):
    """
    True/False if aaa can read schema's Objects
    """

    if not aaa:
        return True

    schema = Schema.from_name(schemaname)
    if schema:
        if schema.has_read_permission(aaa=aaa):
            return True

    return False


def build_related_reply(instances_eav, aaa=None):
    """
    Shared second half of get_related(): given a DataEAV queryset already
    filtered to whatever "points at this object" means for the caller (a
    schema-type field match, an ipv4 value match for ipam_ip via
    app_data.ipam.get_related_ipam_ip(), ...), build and return:

    dict[schemaname] =  {
            displayname: XXXX
            count: ###
            instances:
            - EAVInstance {}
            - EAVInstance {}
            - ...
            }
    if aaa provided, reply is filtered with aaa read permission
    on each schema's instances.
    """

    reply = {}

    # dict of all classname => displayname
    classname2displayname = Schema.displayname_dict()

    unwanted_schemanames = get_unwanted_schemanames()

    for schemaname, displayname in classname2displayname.items():
        # filter unwanted Schema for related
        if schemaname in unwanted_schemanames:
            continue

        if not is_authorized_schema(schemaname=schemaname, aaa=aaa):
            continue

        schema_obj = Schema.from_name(schemaname)
        reply[schemaname] = {}
        reply[schemaname]["displayname"] = displayname
        reply[schemaname]["icon"] = schema_obj.icon if schema_obj else "fa-question"
        reply[schemaname]["count"] = 0
        reply[schemaname]["instances"] = []

    # Loop on instances from EAV - deduplicate by iid
    seen = {}
    for i in instances_eav:
        if i.classname not in reply:
            continue
        if i.iid in seen.get(i.classname, set()):
            continue
        seen.setdefault(i.classname, set()).add(i.iid)
        reply[i.classname]["count"] += 1
        reply[i.classname]["instances"].append(i)

    return reply


def get_related(classname=None, keyname=None, aaa=None):
    """
    Objects referencing classname:keyname via a "schema"-type field.

    OUT: dict[schemaname] =  {
            displayname: XXXX
            count: ###
            instances:
            - EAVInstance {}
            - EAVInstance {}
            - ...
            }
    if aaa provided, reply is filtered with aaa read permission
    on each schema's instances.

    ipam_ip's keyname is an opaque hexip string, never written into a
    "schema" field by anything - see app_data.ipam.get_related_ipam_ip()
    instead, which matches on ipv4-format EAV value (the IP itself, i.e.
    ipam_ip's displayname) rather than on format="schema:ipam_ip"/keyname.
    """

    if not classname or not keyname:
        return {}

    instances_eav = DataEAV.objects.filter(format="schema:" + classname, value__iexact=keyname)

    return build_related_reply(instances_eav, aaa=aaa)
