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

from app_data.permissions import (
    has_group_create_permission,
    has_group_delete_permission,
    has_group_read_permission,
    has_group_update_permission,
)
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 app_user.forms import GroupForm, GroupUploadForm
from app_user.group import (
    group_autogroup_update,
    group_create,  # or update
    group_delete,
    group_get_by_id,
    group_get_form,
    group_get_subgroups,
    group_get_users,
    group_json_response,
    group_search,
    group_update,
    group_yaml_response,
)
from app_user.models import SireneGroup
from django.contrib import messages
from django.shortcuts import redirect, render
from django.utils.translation import gettext as _

from .aaa import start_view

# TODO: check per-group permissions

# ----------------------------------------------------------
# GROUPS
# ----------------------------------------------------------

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

    context = start_view(request, app="iam", view="group_list",
        noauth="app_home:index", perm="p_group_read", noauthz="app_sirene: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=False).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:group_list")

    if page < 1 or size > 10000 or size < 1:
        return redirect("app_user:group_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="group_list", action="export", status="FAIL", data=_("Not allowed"))
            messages.add_message(request, messages.ERROR, _("Not allowed"))
            return redirect("app_sirene:private")
        export_max = int(get_configuration("data", "EXPORT_INTERACTIVE_MAX_SIZE"))
        if count > export_max:
            log(ERROR, aaa=aaa, app="iam", view="group_list", action="export", status="KO", data="Export too big")
            messages.add_message(request, messages.ERROR, _("Export too large for interactive export."))
            return redirect("app_user:group_list")
        groups_all = SireneGroup.objects.filter(is_role=False).order_by('keyname')
        if output == "json":
            log(INFO, aaa=aaa, app="iam", view="group_list", action="export_json", status="OK", data="")
            return group_json_response(groups_all)
        elif output == "yaml":
            log(INFO, aaa=aaa, app="iam", view="group_list", action="export_yaml", status="OK", data="")
            return group_yaml_response(groups_all)

    # Paginated query
    groups = group_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["groups"] = groups
    context["upload_form"] = GroupUploadForm()

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



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

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

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

    group = group_get_by_id(id)
    if not isinstance(group, SireneGroup):
        messages.add_message(request, messages.ERROR, _("Not found"))
        log(WARNING, aaa=aaa, app="iam", view="group", action="detail", status="KO", data=_("Not found") )
        return redirect("app_user:group_list")

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

    # c = group_autogroup_update()
    # update autogroup_users (don't wait for periodic task)
    group_autogroup_update([group])

    # main group object
    context["group"] = group

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

    context["users_direct"] = group_get_users(group, direct=True, computed=False, subgroups=False)
    context["users_computed"] = group_get_users(group, direct=False, computed=True, subgroups=False)
    context["users_indirect"] = group_get_users(group, direct=False, computed=False, subgroups=True)

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


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

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

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

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

    group = None

    if id:
        group = group_get_by_id(id)
        if not group:
            messages.add_message(request, messages.ERROR, _("Not allowed"))
            log(WARNING, aaa=aaa, app="iam", view="group", action="edit", status="KO", data=_("Not allowed") )
            return redirect("app_user:group_list")
        if not has_group_update_permission(aaa=aaa):
            messages.add_message(request, messages.ERROR, _("Not allowed"))
            log(WARNING, aaa=aaa, app="iam", view="group", action="edit", status="KO", data=_("Not allowed") )
            return redirect("app_user:group_list")
    else:
        if not has_group_create_permission(aaa=aaa):
        #if "p_group_create" not in aaa["perms"]:
            messages.add_message(request, messages.ERROR, _("Not allowed"))
            log(WARNING, aaa=aaa, app="iam", view="group", action="create", status="KO", data=_("Not allowed") )
            return redirect("app_user:group_list")


    if request.method == "POST":

        form = GroupForm(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 group:
                group, err = group_update(group, data)

            # create
            else:
                group, err = group_create(data)
                action = "create"

            if err:
                messages.add_message(request, messages.ERROR, _("Failed to save group"))
                log(ERROR, aaa=aaa, app="iam", view="group", action="save", status="KO", data=_("Failed to save group"))

            else:
                revision_add_raw(aaa=aaa, classname="_group", keyname=group.keyname, displayname=group.displayname, action=action)
                messages.add_message(request, messages.SUCCESS, _("Group saved") )
                log(INFO, aaa=aaa, app="iam", view="group", action="save", status="OK", data=f"saved: {group.keyname}")


            return redirect("app_user:group_detail", group.id)

        else:
            # error, keep editing
            messages.add_message(request, messages.ERROR, _("Invalid group form") )
            log(DEBUG, aaa=aaa, app="usiamr", view="group", action="save", status="KO", data=_("Invalid group form"))
            # 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 group:
            form = group_get_form(group)
            context["users"] = []
            #users = group.users.all()
            users = group_get_users(group, subgroups=False, computed=False)

            for i in users:
                item = { "key":i.login, "display":i.displayname , "selected":True}
                context["users"].append(item)

        else:
            context["users"] = []
            form = group_get_form()


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

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


# --------------------------------------------
# delete
# --------------------------------------------
def delete(request, id):
    ''' delete user Group '''

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

    # TODO : check perms / security groups

    gobj = group_get_by_id(id)

    if not gobj:
        log(ERROR, aaa=aaa, app="iam", view="group_delete", action="find", status="FAIL", data=_("Group not found"))
        messages.add_message(request, messages.ERROR, _("Group not found"))
        return redirect("app_user:group_list")
    else:
        if not has_group_delete_permission(aaa=aaa):
            messages.add_message(request, messages.ERROR, _("Not allowed"))
            log(WARNING, aaa=aaa, app="iam", view="group", action="permission", status="KO", data=_("Not allowed") )
            return redirect("app_user:group_list")


    if request.method == "POST":

        group, err = group_delete(gobj)

        if err:
            log(ERROR, aaa=aaa, app="iam", view="group_delete", action="delete", status="FAIL", data=_("Failed to delete group") )
            messages.add_message(request, messages.ERROR, _("Failed to delete group"))
        else:
            revision_add_raw(aaa=aaa, classname="_group", keyname=group.keyname, displayname=group.displayname, action="delete")
            messages.add_message(request, messages.SUCCESS, _("Group deleted ") )
            log(INFO, aaa=aaa, app="iam", view="group_delete", action="delete", status="OK", data=f"deleted: {group.keyname}" )


    return redirect("app_user:group_list")


