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


from app_data.revision import revision_add_raw, revision_get
from app_home.configuration import get_configuration
from app_home.log import DEBUG, ERROR, INFO, WARNING, log
from django.contrib import messages
from django.shortcuts import redirect, render
from django.utils.translation import gettext as _

from .aaa import start_view
from .forms import RoleForm, RoleUploadForm
from .models import SireneGroup
from .role import (
    role_create,  # or update
    role_delete,
    role_expand_to_users,
    role_get_by_id,
    role_get_form,
    role_get_subgroups,
    role_json_response,
    role_search,
    role_update,
    role_yaml_response,
)

# ----------------------------------------------------------
# role list
# ----------------------------------------------------------

def list(request):
    ''' display role (security group) list '''

    context = start_view(request, app="iam", view="role_list", noauth="app_home:index",
        perm="p_role_read", noauthz="app_home:index")
    if context["redirect"]:
        return redirect(context["redirect"])
    aaa = context["aaa"]

    bigset_size = int(get_configuration("data", "DATA_BIGSET_SIZE"))
    count = SireneGroup.objects.filter(is_role=True).count()
    context["count"] = count
    context["bigset"] = True

    # Search query (POST)
    query = ""
    if request.method == "POST":
        if request.POST.get('query'):
            import re
            query = request.POST.get('query')
            m = re.compile(r'[a-zA-Z0-9()_/.-]*$')
            if not m.match(query):
                query = ""
    context["query"] = query

    # Pagination (GET)
    try:
        size = int(request.GET.get("size", bigset_size))
        page = int(request.GET.get("page", 1))
    except Exception:
        return redirect("app_user:role_list")

    if page < 1 or size > 10000 or size < 1:
        return redirect("app_user:role_list")

    # Export (full dataset, not paginated)
    output = request.GET.get("o", "")
    if output != "":
        if 'p_iam_export' not in aaa["perms"]:
            log(WARNING, aaa=aaa, app="iam", view="role", action="export", status="FAIL", data=_("Not allowed"))
            messages.add_message(request, messages.ERROR, _("Not allowed"))
            return redirect("app_user:role_list")
        export_max = int(get_configuration("data", "EXPORT_INTERACTIVE_MAX_SIZE"))
        if count > export_max:
            log(ERROR, aaa=aaa, app="iam", view="role", action="export", status="KO", data="Export too big")
            messages.add_message(request, messages.ERROR, _("Export too large for interactive export."))
            return redirect("app_user:role_list")
        roles_all = SireneGroup.objects.filter(is_role=True).order_by('keyname')
        if output == "json":
            log(INFO, aaa=aaa, app="iam", view="role_list", action="export_json", status="OK", data="")
            return role_json_response(roles_all)
        elif output == "yaml":
            log(INFO, aaa=aaa, app="iam", view="role_list", action="export_yaml", status="OK", data="")
            return role_yaml_response(roles_all)

    # Paginated query
    roles = role_search(query=query, page=page, size=size)

    # Pagination context
    context["size"] = size
    context["page"] = page
    page_last = int(count / size) + 1
    context["page_prev"] = max(page - 1, 1)
    context["page_first"] = (page == 1)
    context["page_current"] = (1 < page < page_last)
    context["page_last"] = page_last
    context["page_last_active"] = (page >= page_last)
    context["page_next"] = min(page + 1, page_last)

    context["roles"] = roles
    context["upload_form"] = RoleUploadForm()

    return render(request, 'app_user/role_list.html', context)

# --------------------------------------------
# detail
# --------------------------------------------

def detail(request, id=None):
    ''' display role detail '''

    context = start_view(request, app="iam", view="role_detail",
        noauth="app_user:private", perm="p_role_read", noauthz="app_user:private")
    if context["redirect"]:
        return redirect(context["redirect"])
    aaa = context["aaa"]

    role = role_get_by_id(id)
    if not role:
        messages.add_message(request, messages.ERROR, _("Not allowed"))
        log(WARNING, aaa=aaa, app="iam", view="role", action="detail", status="KO", data=_("Not allowed") )
        return redirect("app_user:role_list")



    subgroups_indirect = role_get_subgroups(role, done=[])
    tmp = role.subgroups.all()
    subgroups_indirect = [i for i in subgroups_indirect if i not in tmp]
    context["subgroups_indirect"] = subgroups_indirect

    users_indirect = role_expand_to_users([], [role])
    tmp = role.users.all()
    users_indirect = [i for i in users_indirect if i not in tmp]
    context["users_indirect"] = users_indirect

    # revisions - V3.23
    context['revisions'] = revision_get(classname="_role", keyname=role.keyname)

    # can use YAML Editor ?
    if 'p_data_import' in aaa['perms']:
        context['ui_texteditor'] = True


    context["role"] = role
    return render(request, 'app_user/role_detail.html', context)


# --------------------------------------------
# role delete
# --------------------------------------------

def delete(request, id=None):
    ''' delete user Group '''

    context = start_view(request, app="iam", view="role_delete",
        noauth="app_user:private", perm="p_role_delete", noauthz="app_sirene:index")
    if context["redirect"]:
        return redirect(context["redirect"])
    aaa = context["aaa"]

    if id:
        gobj = role_get_by_id(id)
        if not gobj:
            log(ERROR, aaa=aaa, app="iam", view="role_delete", action="find", status="KO", data=_("Role not found"))
            messages.add_message(request, messages.ERROR, _("Role not found"))
            return redirect("app_user:role_list")

    # role ?
    if not gobj.is_role:
        log(ERROR, aaa=aaa, app="iam", view="role_delete", action="find", status="KO", data=_("Not a role"))
        messages.add_message(request, messages.ERROR, _("Not a role"))
        return redirect("app_user:role_list")

    if request.method == "POST":

        role, err = role_delete(gobj)

        if err:
            log(ERROR, aaa=aaa, app="iam", view="role_delete", action="delete", status="KO", data=_("Failed to delete role") )
            messages.add_message(request, messages.ERROR, _("Failed to delete role"))
        else:
            revision_add_raw(aaa=aaa, classname="_role", keyname=role.keyname, displayname=role.displayname, action="delete")
            messages.add_message(request, messages.SUCCESS, _("Role deleted") )
            log(INFO, aaa=aaa, app="iam", view="role_delete", action="delete", status="OK", data=f"Role deleted : {role.keyname}" )


    return redirect("app_user:role_list")


# --------------------------------------------
# edit
# --------------------------------------------
def edit(request, id=None):
    ''' usergroup  edit form'''

    context = start_view(request, app="iam", view="role_edit",
        noauth="app_user:private", perm="p_role_update", noauthz="app_sirene:index")
    if context["redirect"]:
        return redirect(context["redirect"])
    aaa = context["aaa"]


    role = None
    if id:
        role = role_get_by_id(id)
        if not role:
            messages.add_message(request, messages.ERROR, _("Not allowed"))
            log(WARNING, aaa=aaa, app="iam", view="role", action="edit", status="KO", data=_("Not allowed") )
            return redirect("app_user:role_list")
    else:
        if "p_role_create" not in aaa["perms"]:
            messages.add_message(request, messages.ERROR, _("Not allowed"))
            log(WARNING, aaa=aaa, app="iam", view="role", action="create", status="KO", data=_("Not allowed") )
            return redirect("app_user:role_list")

    if request.method == "POST":

        form = RoleForm(request.POST)

        if form.is_valid():

            # data + add users (outside managed django form)
            data = form.cleaned_data
            users = request.POST.getlist("users",default=[])
            data["users"] = users

            action = "edit"
            # update
            if role:
                role, err = role_update(role, data)

            # create
            else:
                role, err = role_create(data)
                action = "create"

            # success ?
            if err:
                messages.add_message(request, messages.ERROR, _("Failed to save role"))
                log(ERROR, aaa=aaa, app="iam", view="role_edit", action="POST", status="KO", data=_("Failed to save role"))

            else:
                revision_add_raw(aaa=aaa, classname="_role", keyname=role.keyname, displayname=role.displayname, action=action)
                messages.add_message(request, messages.SUCCESS, _("Role saved") )
                log(INFO, aaa=aaa, app="iam", view="role_edit", action="POST", status="OK", data=f"Role saved : {role.keyname}")


            return redirect("app_user:role_detail", role.id)

        else:
            messages.add_message(request, messages.ERROR, _("Invalid role form") )
            log(DEBUG, aaa=aaa, app="iam", view="role_edit", action="POST", status="KO", data=_("Invalid role form"))
            # keep editing, add out of form users attribute
            context["users"] = []
            users = request.POST.getlist("users",default=[])
            for i in users:
                item = { "key":i, "display":i, "selected":True}
                context["users"].append(item)
    # GET
    else:
        if role:
            form = role_get_form(role)
            context["users"] = []
            users = role.users.all()
            for i in users:
                item = { "key":i.login, "display":i.displayname , "selected":True}
                context["users"].append(item)
        else:
            form = role_get_form()
            context["users"] = []


    context["form"] = form
    if role:
        context["role"] = role

    return render(request, 'app_user/role_edit.html', context)

