# (c) cavaliba.com - data - permissions.py

import json
import re

import yaml
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 _


#  -------
# aaa
#  -------
def aaa_perms_valid(aaa):
    try:
        if type(aaa["perms"]) is not list:
            return False
    except Exception:
        return False
    return True


#  -------
# SCHEMA
#  -------
def has_schema_read_permission(aaa=None):
    """permission to read all schemas definitions and fields"""

    if not aaa_perms_valid(aaa):
        return False

    if "p_schema_read" in aaa["perms"]:
        return True
    if "p_schema_write" in aaa["perms"]:
        return True
    return False


def has_schema_write_permission(aaa=None):

    if not aaa_perms_valid(aaa):
        return False

    """ permission to write all schemas definitions and fields"""
    if "p_schema_write" in aaa["perms"]:
        return True
    return False


#  ----
# IAM
#  ----
def has_iam_export_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_iam_export" in aaa["perms"]:
        return True
    return False


# user read
def has_user_read_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_user_read" in aaa["perms"]:
        return True
    return False


# user create
def has_user_create_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_user_create" in aaa["perms"]:
        return True
    return False


# user update
def has_user_update_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_user_update" in aaa["perms"]:
        return True
    return False


# user delete
def has_user_delete_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_user_delete" in aaa["perms"]:
        return True
    return False


# group read
def has_group_read_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_group_read" in aaa["perms"]:
        return True
    return False


# group create
def has_group_create_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_group_create" in aaa["perms"]:
        return True
    return False


# group update
def has_group_update_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_group_update" in aaa["perms"]:
        return True
    return False


# group delete
def has_group_delete_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_group_delete" in aaa["perms"]:
        return True
    return False


# role read
def has_role_read_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_role_read" in aaa["perms"]:
        return True
    return False


# role create
def has_role_create_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_role_create" in aaa["perms"]:
        return True
    return False


# role update
def has_role_update_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_role_update" in aaa["perms"]:
        return True
    return False


# role delete
def has_role_delete_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_role_delete" in aaa["perms"]:
        return True
    return False


# permission read
def has_permission_read_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_permission_read" in aaa["perms"]:
        return True
    return False


# permission create
def has_permission_create_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_permission_create" in aaa["perms"]:
        return True
    return False


# permission update
def has_permission_update_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_permission_update" in aaa["perms"]:
        return True
    return False


# permission delete
def has_permission_delete_permission(aaa=None):
    if not aaa_perms_valid(aaa):
        return False
    if "p_permission_delete" in aaa["perms"]:
        return True
    return False


# -------------------------------------------------------
# PERMISSION CRUD
# -------------------------------------------------------


def permission_all_keynames():
    from app_user.models import SirenePermission

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


def permission_get_all():
    from app_user.models import SirenePermission

    return SirenePermission.objects.all()


def permission_search(query=None, page=1, size=10):
    from django.db.models import Q

    from app_user.models import SirenePermission

    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):
    from app_user.models import SirenePermission

    return SirenePermission.objects.filter(pk=pid).first()


def permission_get_by_name(keyname):
    from app_user.models import SirenePermission

    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_init(data):
    from app_user.models import SirenePermission

    keyname = data.get("keyname", None)
    if not keyname:
        return None, "permission_init: missing keyname"
    entry = permission_get_by_name(keyname)
    if entry:
        return entry, None
    entry = SirenePermission()
    return permission_update(entry, data)


def permission_create(data):
    from app_user.models import SirenePermission

    keyname = data.get("keyname", None)
    if not keyname:
        return None, "permission_create: missing keyname"
    entry = permission_get_by_name(keyname)
    if not entry:
        entry = SirenePermission()
    return permission_update(entry, data)


def permission_update(iobj, data):
    if not iobj:
        return None, "permission_update: obj not found"
    if not data:
        return None, "permission_update: data not found"

    for attrib in ["keyname", "displayname", "description"]:
        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)


def bootstrap_permissions(datadict):
    from app_home.log import WARNING, log
    from app_user.models import SirenePermission

    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:
        from app_home.log import WARNING, log

        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")

    if action == "init":
        if not has_permission_create_permission(aaa=aaa):
            from app_home.log import WARNING, log

            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):
            from app_home.log import WARNING, log

            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):
            from app_home.log import WARNING, log

            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):
            from app_home.log import WARNING, log

            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):
    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"
        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


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


class _PermissionYamlDumper(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=_PermissionYamlDumper, sort_keys=False
    )
    response = HttpResponse(filedata, content_type="text/yaml")
    response["Content-Disposition"] = 'attachment; filename="permissions.yaml"'
    return response
