# (c) cavaliba.com - home - views.py

import re

from django.conf import settings
from django.contrib import messages
from django.db.models import Q
from django.http import HttpResponse
from django.shortcuts import redirect, render
from django.utils.translation import gettext as _

from app_data.aaa import start_view
from app_data.data import update_bigset
from app_data.eav import task_eav_purge, task_eav_refresh
from app_data.models import DataRevision
from app_home.models import DashboardApp

from .configuration import get_configuration, get_initial_form, get_post_form, save_form
from .home import convert_icon, get_cavaliba_apps
from .log import DEBUG, INFO, WARNING, log, purge
from .models import CavalibaLog

# '' or 'tw4'
HTML_TEMPLATE_PATH = settings.CAVALIBA_HTML_FRAMEWORK


# -----------------------------------------
# status page
# -----------------------------------------
def status(request):
    return HttpResponse("OK")


# -----------------------------------------
# welcome
# -----------------------------------------

# def welcome(request):

#     context = start_view(request, app="home", view="welcome", noauth="app_sirene:index", perm="p_home_access")
#     aaa = context["aaa"]

#     if context["redirect"]:
#         return redirect(context["redirect"])


# -----------------------------------------
# private - private_page
# -----------------------------------------


def private(request):

    context = start_view(
        request,
        app="home",
        view="private",
        noauth="app_sirene:index",
        perm="p_home_access",
        noauthz="app_sirene:index",
    )
    if context["redirect"]:
        return redirect(context["redirect"])
    aaa = context["aaa"]

    paginated = []
    pagelist = []
    index = {}  # page => [class1, class2]
    default_name = get_configuration("home", "GLOBAL_APPNAME")

    apps = DashboardApp.objects.all().prefetch_related("permission").order_by("order")
    for app in apps:
        if not app.is_enabled:
            continue

        app.is_allowed = False
        try:
            if app.permission.keyname in aaa["perms"]:
                app.is_allowed = True
        except Exception as e:
            print(e)

        if app.keyname == "home":
            continue

        app.icon = convert_icon(app.icon)

        section = app.dashboard_section
        if not section:
            section = default_name
        if len(section) == 0:
            section = default_name
        if section not in index:
            index[section] = []
            pagelist.append(section)
        index[section].append(app)
        default_name = section

    # paginate
    for p in pagelist:
        paginated.append([p, index[p]])

    log(DEBUG, aaa=aaa, app="home", view="dash", action="view", status="OK")

    context["paginated"] = paginated
    return render(request, f"app_home/{HTML_TEMPLATE_PATH}/private.html", context)


# -----------------------------------------
# configuration
# -----------------------------------------


def configuration(request, appname=None):

    # context = start_view(request, app="home", view="private", noauth="app_sirene:index", perm="p", noauthz="app_sirene:index")
    context = start_view(
        request,
        app="home",
        view="configuration",
        noauth="app_home:index",
        perm="p_conf_admin",
        noauthz="app_sirene:index",
    )
    if context["redirect"]:
        return redirect(context["redirect"])
    aaa = context["aaa"]

    if appname:
        if not DashboardApp.objects.filter(keyname=appname).first():
            return redirect("app_home:index")
        # appobj = get_app_by_name(appname)
        # if not appobj:
        #     return redirect("app_home:index")

    if request.method == "POST":
        form = get_post_form(request, appname=appname)

        if form.is_valid():
            save_form(form, appname=appname)
            messages.add_message(request, messages.SUCCESS, _("Configuration updated"))
            log(
                INFO,
                aaa=aaa,
                app="home",
                view="configuration",
                action="update",
                status="OK",
                data=f"app {appname}",
            )
            return redirect("app_home:configuration", appname)
        else:
            messages.add_message(request, messages.ERROR, _("Invalid configuration"))

    else:
        form = get_initial_form(appname)

    if appname:
        context["appname"] = appname

    context["apps"] = get_cavaliba_apps()
    context["form"] = form
    return render(request, f"app_home/{HTML_TEMPLATE_PATH}/configuration.html", context)


# -----------------------------------------
# log
# -----------------------------------------


def logview(request, level="info"):

    context = start_view(
        request,
        app="home",
        view="log",
        noauth="app_sirene:index",
        perm="p_log_view",
        noauthz="app_home:index",
    )
    if context["redirect"]:
        return redirect(context["redirect"])
    aaa = context["aaa"]

    # purge ?
    if request.method == "POST":
        if request.POST.get("purge"):
            if "p_log_admin" in aaa["perms"]:
                count = purge(aaa=aaa)
                messages.add_message(request, messages.SUCCESS, _("Logs purged: ") + str(count))
                log(
                    WARNING,
                    aaa=aaa,
                    app="home",
                    view="log",
                    action="purge",
                    status="OK",
                    data=f"{count} removed",
                )
                return redirect("app_home:log")

    # bigset or not
    count = CavalibaLog.objects.count()
    bigset = True
    context["bigset"] = bigset
    context["count"] = count

    # Filter POST (form)
    # -------------------
    # query = request.GET.get("q", "")
    query = ""
    if request.method == "POST":
        if request.POST.get("query"):
            query = request.POST.get("query")
    if request.method == "GET":
        if request.GET.get("query"):
            query = request.GET.get("query")
    if query:
        m = re.compile(r"[a-zA-Z0-9()_/.-]*$")
        if not m.match(query):
            query = ""
    context["query"] = query

    # partial query + paginate if bigset
    try:
        size = int(request.GET.get("size", 100))
        page = int(request.GET.get("page", 1))
    except Exception:
        return redirect("app_home:log")

    if page < 1 or size > 10000 or size < 1:
        return redirect("app_home:log")

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

    if len(query) > 0:
        if level not in ["debug", "info", "warning", "error", "critical"]:
            level = "debug"

        if level == "info":
            level_display = _("INFO")
            logs = (
                CavalibaLog.objects.all()
                .order_by("-id")
                .filter(level__in=["INFO", "WARNING", "ERROR", "CRITICAL"])
                .filter(
                    Q(app__icontains=query)
                    | Q(username__icontains=query)
                    | Q(view__icontains=query)
                    | Q(action__icontains=query)
                    | Q(data__icontains=query)
                    | Q(status__icontains=query)
                    | Q(user_ip__icontains=query)
                )[offset:limit]
            )

        elif level == "warning":
            level_display = _("WARNING")
            logs = (
                CavalibaLog.objects.all()
                .order_by("-id")
                .filter(level__in=["WARNING", "ERROR", "CRITICAL"])
                .filter(
                    Q(app__icontains=query)
                    | Q(username__icontains=query)
                    | Q(view__icontains=query)
                    | Q(action__icontains=query)
                    | Q(data__icontains=query)
                    | Q(status__icontains=query)
                    | Q(user_ip__icontains=query)
                )[offset:limit]
            )

        elif level == "error":
            level_display = _("ERROR")
            logs = (
                CavalibaLog.objects.all()
                .order_by("-id")
                .filter(level__in=["ERROR", "CRITICAL"])
                .filter(
                    Q(app__icontains=query)
                    | Q(username__icontains=query)
                    | Q(view__icontains=query)
                    | Q(action__icontains=query)
                    | Q(data__icontains=query)
                    | Q(status__icontains=query)
                    | Q(user_ip__icontains=query)
                )[offset:limit]
            )

        elif level == "critical":
            level_display = _("CRITICAL")
            logs = (
                CavalibaLog.objects.all()
                .order_by("-id")
                .filter(level="CRITICAL")
                .filter(
                    Q(app__icontains=query)
                    | Q(username__icontains=query)
                    | Q(view__icontains=query)
                    | Q(action__icontains=query)
                    | Q(data__icontains=query)
                    | Q(status__icontains=query)
                    | Q(user_ip__icontains=query)
                )[offset:limit]
            )

        else:
            level_display = _("DEBUG")
            logs = (
                CavalibaLog.objects.all()
                .order_by("-id")
                .filter(
                    Q(app__icontains=query)
                    | Q(username__icontains=query)
                    | Q(view__icontains=query)
                    | Q(action__icontains=query)
                    | Q(data__icontains=query)
                    | Q(status__icontains=query)
                    | Q(user_ip__icontains=query)
                )[offset:limit]
            )
    else:
        if level not in ["debug", "info", "warning", "error", "critical"]:
            level = "info"

        if level == "info":
            level_display = _("INFO")
            logs = (
                CavalibaLog.objects.all()
                .order_by("-id")
                .filter(level__in=["INFO", "WARNING", "ERROR", "CRITICAL"])[offset:limit]
            )

        elif level == "warning":
            level_display = _("WARNING")
            logs = (
                CavalibaLog.objects.all()
                .order_by("-id")
                .filter(level__in=["WARNING", "ERROR", "CRITICAL"])[offset:limit]
            )

        elif level == "error":
            level_display = _("ERROR")
            logs = (
                CavalibaLog.objects.all()
                .order_by("-id")
                .filter(level__in=["ERROR", "CRITICAL"])[offset:limit]
            )

        elif level == "critical":
            level_display = _("CRITICAL")
            logs = CavalibaLog.objects.all().order_by("-id").filter(level="CRITICAL")[offset:limit]

        else:
            level_display = _("DEBUG")
            logs = CavalibaLog.objects.all().order_by("-id")[offset:limit]

    # PREV | FIRST || CURRENT or ... || LAST | NEXT
    context["size"] = size
    context["page"] = page
    page_last = int(count / size) + 1

    if page > 1:
        context["page_prev"] = page - 1
    else:
        context["page_prev"] = page

    if page == 1:
        context["page_first"] = True
    else:
        context["page_first"] = False

    if page > 1 and page < page_last:
        context["page_current"] = True
    else:
        context["page_current"] = False

    context["page_last"] = page_last
    if page < page_last:
        context["page_last_active"] = False
    else:
        context["page_last_active"] = True

    if page < page_last:
        context["page_next"] = page + 1
    else:
        context["page_next"] = page

    context["level"] = level_display
    context["logs"] = logs
    return render(request, f"app_home/{HTML_TEMPLATE_PATH}/log.html", context)


# ----------------------------------------------------------------------------------------------------
# admin tools MAIN
# -----------------------------------------------------------------------------------------------------


def admintools(request):

    context = start_view(
        request,
        app="admintools",
        view="main",
        noauth="app_home:index",
        perm="p_admintools",
        noauthz="app_sirene:index",
    )
    if context["redirect"]:
        return redirect(context["redirect"])

    return render(request, f"app_home/{HTML_TEMPLATE_PATH}/admintools.html", context)


# -----------------------------------------
# admin tools - update bigset
# -----------------------------------------


def admintools_updatebigset(request):

    context = start_view(
        request,
        app="admintools",
        view="update_bigset",
        noauth="app_home:index",
        perm="p_admintools",
        noauthz="app_sirene:index",
    )
    if context["redirect"]:
        return redirect(context["redirect"])
    aaa = context["aaa"]

    if request.method == "POST":
        messages.add_message(request, messages.SUCCESS, _("Task started..."))
        update_bigset(aaa=aaa)
        messages.add_message(request, messages.SUCCESS, _("Task done."))
        log(
            WARNING,
            aaa=aaa,
            app="home",
            view="admintools",
            action="updatebigset",
            status="OK",
            data="done",
        )

    return redirect("app_home:admintools")


# -----------------------------------------
# admin tools - EAV refresh
# -----------------------------------------
def admintools_eavrefresh(request):

    context = start_view(
        request,
        app="admintools",
        view="eav_refresh",
        noauth="app_home:index",
        perm="p_admintools",
        noauthz="app_sirene:index",
    )
    if context["redirect"]:
        return redirect(context["redirect"])
    aaa = context["aaa"]

    if request.method == "POST":
        messages.add_message(request, messages.SUCCESS, _("EAV Refresh - long task started..."))
        log(
            WARNING,
            aaa=aaa,
            app="home",
            view="admintools",
            action="eav_refresh",
            status="OK",
            data="started...",
        )
        task_eav_refresh.delay(dryrun=False, force=False)

    return redirect("app_home:admintools")


# -----------------------------------------
# admin tools - EAV purge
# -----------------------------------------


def admintools_eavpurge(request):

    context = start_view(
        request,
        app="admintools",
        view="eav_purge",
        noauth="app_home:index",
        perm="p_admintools",
        noauthz="app_sirene:index",
    )
    if context["redirect"]:
        return redirect(context["redirect"])
    aaa = context["aaa"]

    if request.method == "POST":
        messages.add_message(request, messages.SUCCESS, _("EAV Purge - long task started..."))
        log(
            WARNING,
            aaa=aaa,
            app="home",
            view="admintools",
            action="eav_purge",
            status="OK",
            data="started...",
        )
        task_eav_purge.delay(dryrun=False)

    return redirect("app_home:admintools")


# -----------------------------------------
# admin tools - Revision
# -----------------------------------------


def admintools_revision(request):

    context = start_view(
        request,
        app="admintools",
        view="revision",
        noauth="app_home:index",
        perm="p_admintools",
        noauthz="app_sirene:index",
    )
    if context["redirect"]:
        return redirect(context["redirect"])
    aaa = context["aaa"]

    # Get pagination parameters from GET request
    try:
        page = int(request.GET.get("page", 1))
        size = int(request.GET.get("size", 1000))
    except Exception:
        page = 1
        size = 1000

    # Calculate offset for pagination
    offset = (page - 1) * size

    # Retrieve revisions ordered by date descending with pagination
    revisions = DataRevision.objects.all().order_by("-date")[offset : offset + size]

    context["revisions"] = revisions
    context["count"] = DataRevision.objects.count()
    context["page"] = page
    context["size"] = size

    log(
        DEBUG,
        aaa=aaa,
        app="home",
        view="admintools",
        action="revision",
        status="OK",
        data="view accessed",
    )

    return render(request, f"app_home/{HTML_TEMPLATE_PATH}/revision.html", context)
