# (c) cavaliba.com - IAM - permission.py

import json
import re

import yaml
from app_data.permissions import (
    has_permission_create_permission,
    has_permission_delete_permission,
    has_permission_update_permission,
)
from app_home.log import WARNING, log
from django.forms.models import model_to_dict
from django.http import HttpResponse
from django.utils import timezone
from django.utils.translation import gettext as _

from .models import SirenePermission


# ------------------------------------
# get all perms
# ------------------------------------
def permission_all_keynames():

    perms = []
    dbperms = SirenePermission.objects.all()
    for p in dbperms:
        perms.append(p.keyname)
    return perms


def permission_get_all():
    return SirenePermission.objects.all()


def permission_search(query=None, page=1, size=10):

    from django.db.models import Q

    m = re.compile(r'[a-zA-Z0-9()_/.-]*$')
    if query and not m.match(query):
        return []

    offset = (page - 1) * size
    limit = offset + size

    qs = SirenePermission.objects.order_by('keyname')

    if query:
        qs = qs.filter(
            Q(keyname__icontains=query) |
            Q(displayname__icontains=query) |
            Q(description__icontains=query)
        )

    return qs[offset:limit]



def permission_get_by_id(pid):
    return SirenePermission.objects.filter(pk=pid).first()


def permission_get_by_name(keyname):
    return SirenePermission.objects.filter(keyname=keyname).first()


def permission_get_by_data(data):

    keyname = data.get('keyname', None)
    if not keyname:
        return
    return  permission_get_by_name(keyname)




# def permission_set(keyname=None, displayname=None, description=None):

#     ''' create/update a single permission in Database '''

#     if not keyname:
#         return

#     p = permission_get_by_name(keyname)
#     if not p:
#         p = SirenePermission()
#         p.keyname = keyname

#     if displayname:
#         p.displayname = displayname

#     if description:
#         p.description = description

#     p.save()

#     return p




def permission_init(data):

    keyname = data.get('keyname', None)
    if not keyname:
        return None, "permission_init: missing keyname"

    # skip if exists
    entry = permission_get_by_name(keyname)
    if entry:
        return entry, None

    entry = SirenePermission()
    return permission_update(entry, data)



def permission_create(data):

    keyname = data.get('keyname', None)
    if not keyname:
        return None, "permission_create: missing keyname"

    # create or update
    entry = permission_get_by_name(keyname)
    if not entry:
        entry = SirenePermission()

    return permission_update(entry, data)


def permission_update(iobj, data):
    ''' update Object with data dict info'''

    attributs =  [
        "keyname", "displayname", "description",
    ]

    if not iobj:
        return None, "permission_update: obj not found"

    if not data:
        return None, "permission_update: data not found"

    for attrib in attributs:
        if attrib in data:
            try:
                setattr(iobj, attrib, data[attrib])
            except Exception:
                pass

    iobj.last_update = timezone.now()

    iobj.save()
    return iobj, None


def permission_update_by_data(data):

    iobj = permission_get_by_data(data)
    if iobj:
        return permission_update(iobj, data)
    return None, "permission_update: not found"


def permission_delete(iobj):

    if not iobj:
        return False, "permission_delete: not found"

    if iobj.is_builtin:
        return False, "permission_delete: is builtin"

    try:
        iobj.delete()
        return iobj, None
    except Exception as e:
        return False, f"permission_delete: {e}"


def permission_delete_by_id(pid):
    iobj = permission_get_by_id(pid)
    return permission_delete(iobj)


def permission_delete_by_data(data):
    iobj = permission_get_by_data(data)
    return permission_delete(iobj)

# -------------------------------------------------------
# IMPORTS
# -------------------------------------------------------

# when bootstraping Cavaliba, no permission exists yet
# create first permission before (home/)
def bootstrap_permissions(datadict):

    # data = {
    #     "keyname": "p_permission_create",
    #     "description": "Built-in IAM permission : create (bootstrap)",
    #     "displayname": "p_permission_create"
    #     [_action: delete]
    # }


    for data in datadict:

        keyname = data.get("keyname", None)
        if not keyname:
            continue


        if '_action' in data:
            if data['_action'] == 'delete':
                try:
                    SirenePermission.objects.filter(keyname=keyname).delete()
                except Exception as e:
                    print("ERR: ", e)
                continue


        entry = SirenePermission.objects.filter(keyname=keyname).first()

        if not entry:
            entry = SirenePermission()

        entry.is_builtin = True
        try:
            entry.keyname = data['keyname']
            entry.displayname = data['keyname']
        except Exception:
            pass
        try:
            entry.description = data['description']
        except Exception:
            pass

        entry.save()

    count = len(datadict)
    log(WARNING, app="iam", view="permission", action="bootstrap", status="OK", data=f"{count} permissions")


    return count



def load_permission(datadict=None, verbose=None, aaa=None):

    if not datadict:
        return "load_permission: no data"

    if not aaa:
        log(WARNING, aaa=aaa, app="iam", view="permission", action="load", status="DENY", data=_("Not allowed"))
        return "load_permission: no permission"


    keyname = datadict.get("keyname", None)
    if not keyname:
        return "load_permission: no keyname"

    action = datadict.get("_action", "create")

    err = None

    # if action == "init_builtin":
    #     r = permission_init(datadict)
    if action == "init":
        if not has_permission_create_permission(aaa=aaa):
            log(WARNING, aaa=aaa, app="iam", view="permission", action="init", status="DENY", data=_("Not allowed"))
            return f"load_permission: init not allowed for {keyname}"
        perm, err = permission_init(datadict)

    elif action == "create":
        if not has_permission_create_permission(aaa=aaa):
            log(WARNING, aaa=aaa, app="iam", view="permission", action="create", status="DENY", data=_("Not allowed"))
            return f"load_permission: create not allowed for {keyname}"
        perm, err = permission_create(datadict)

    elif action == "update":
        if not has_permission_update_permission(aaa=aaa):
            log(WARNING, aaa=aaa, app="iam", view="permission", action="update", status="DENY", data=_("Not allowed"))
            return f"load_permission: update not allowed for {keyname}"
        perm, err = permission_update_by_data(datadict)

    elif action == "delete":
        if not has_permission_delete_permission(aaa=aaa):
            log(WARNING, aaa=aaa, app="iam", view="permission", action="delete", status="DENY", data=_("Not allowed"))
            return f"load_permission: delete not allowed for {keyname}"
        perm, err = permission_delete_by_data(datadict)

    else:
        return f"load_permission: unknown action: {action}"

    if err:
        return f"load_permission: {err}"
    return

# -------------------------------------------------------
# EXPORT
# -------------------------------------------------------

def permission_listdict_format(permissions):
    ''' list of  Models to  list of dict '''

    dict_attributs =  ["keyname", "is_builtin", "displayname", "is_enabled","description" ]

    datalist = []
    for permission in permissions:
        m = model_to_dict(permission, fields=dict_attributs)
        m["classname"] = "_permission"

        # remove null values
        m2= {}
        for k,v in m.items():
            if not isinstance(v,bool):
                if v:
                    m2[k] = v
            else:
                m2[k] = v

        m2["id"] = permission.id
        datalist.append(m2)

    return datalist


# JSON
def permission_json_response(items):
    datalist = permission_listdict_format(items)
    filedata = json.dumps(datalist, indent=4, ensure_ascii = False)
    response = HttpResponse(filedata, content_type='text/json')
    response['Content-Disposition'] = 'attachment; filename="permissions.json"'
    return response

# YAML
class MyYamlDumper(yaml.SafeDumper):
    def write_line_break(self, data=None):
        super().write_line_break(data)
        if len(self.indents) < 2:
            super().write_line_break()


def permission_yaml_response(items):
    datalist = permission_listdict_format(items)
    filedata = yaml.dump(datalist, allow_unicode=True, Dumper=MyYamlDumper, sort_keys=False)
    response = HttpResponse(filedata, content_type='text/yaml')
    response['Content-Disposition'] = 'attachment; filename="permissions.yaml"'
    return response
