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


import logging
from datetime import timedelta

from django.utils import timezone

from app_home.configuration import get_configuration

from .models import CavalibaLog

logger = logging.getLogger(__name__)


TRACE = "TRACE"
DEBUG = "DEBUG"
INFO = "INFO"
WARNING = "WARNING"
ERROR = "ERROR"
CRITICAL = "CRITICAL"


def log(level, app="", view="", action="", status="", data="", aaa=None, user_ip="-"):

    log_to_db = True
    log_handler = False

    alog = CavalibaLog()

    alog.created_at = timezone.now()
    alog.level = level

    alog.app = app
    alog.view = view
    alog.action = action
    alog.status = status
    alog.data = data

    if aaa:
        alog.user_ip = aaa.get("user_ip", "-")
        # switch in Logs, username is source account, impersonate is impersonated account
        if len(aaa.get("impersonate_by", "")) > 0:
            alog.impersonate = aaa.get("username", "-")
            alog.username = aaa["impersonate_by"]
        else:
            alog.impersonate = "-"
            alog.username = aaa.get("username", "")
    else:
        alog.impersonate = "-"
        alog.username = "-"
        alog.user_ip = user_ip

    # exclude some IPs
    log_excluded_ip = get_configuration(appname="home", keyname="LOG_EXCLUDED_IP").split(" ")
    if "*" in log_excluded_ip:
        log_to_db = False

    if len(log_excluded_ip) > 0:
        if alog.user_ip in log_excluded_ip:
            log_to_db = False

    # app logging to DB
    # -----------------
    # NEXT : config switch
    if level == "TRACE":
        log_to_db = False

    if level == "DEBUG":
        log_debug = get_configuration(appname="home", keyname="LOG_DEBUG")
        if log_debug != "yes":
            log_to_db = False

    if log_to_db:
        try:
            alog.save()
        except Exception as e:
            print(e)

    # Django logging with CavalibaLogHandler
    #  -------------------------------------
    if log_handler:
        logstring = f"{alog.user_ip} s={status} app={app} view={view} action={action} user={alog.username} impersonate={alog.impersonate} data='{data}'"
        # logstring = f"{data}"

        if level == TRACE:
            logger.debug(logstring)
        elif level == DEBUG:
            logger.debug(logstring)
        elif level == INFO:
            logger.info(logstring)
        elif level == WARNING:
            logger.warning(logstring)
        elif level == ERROR:
            logger.error(logstring)
        elif level == CRITICAL:
            logger.critical(logstring)


# ----------------


def log_get_count():
    return CavalibaLog.objects.count()


def log_list(start=0, size=100):
    return CavalibaLog.objects.all().order_by("-id")[start:size]


# ----------------


def purge_all():

    count = CavalibaLog.objects.all().delete()[0]
    log(
        WARNING,
        app="CLI_manage",
        view="log",
        action="purge_all",
        status="OK",
        data=f"{count} entries removed",
    )
    return count


def purge_level(level, keep_days):

    if keep_days == 0:
        count = CavalibaLog.objects.filter(level=level).delete()[0]
    else:
        count = CavalibaLog.objects.filter(
            level=level, created__lte=timezone.now() - timedelta(days=keep_days)
        ).delete()[0]

    return count


def purge(aaa=None):

    count = 0

    # DEBUG
    keep_days = int(get_configuration(appname="home", keyname="LOG_KEEP_DAYS_DEBUG"))
    subcount = purge_level("DEBUG", keep_days)
    log(
        INFO,
        app="home",
        view="log",
        action="purge",
        status="OK",
        data=f"{subcount} DEBUG entries removed",
    )
    count += subcount

    # INFO
    keep_days = int(get_configuration(appname="home", keyname="LOG_KEEP_DAYS_INFO"))
    subcount = purge_level("INFO", keep_days)
    log(
        INFO,
        app="home",
        view="log",
        action="purge",
        status="OK",
        data=f"{subcount} INFO entries removed",
    )
    count += subcount

    # WARNING
    keep_days = int(get_configuration(appname="home", keyname="LOG_KEEP_DAYS_WARNING"))
    subcount = purge_level("WARNING", keep_days)
    log(
        INFO,
        app="home",
        view="log",
        action="purge",
        status="OK",
        data=f"{subcount} WARNING entries removed",
    )
    count += subcount

    # ERROR
    keep_days = int(get_configuration(appname="home", keyname="LOG_KEEP_DAYS_ERROR"))
    subcount = purge_level("ERROR", keep_days)
    log(
        INFO,
        app="home",
        view="log",
        action="purge",
        status="OK",
        data=f"{subcount} ERROR entries removed",
    )
    count += subcount

    # CRITICAL
    keep_days = int(get_configuration(appname="home", keyname="LOG_KEEP_DAYS_CRITICAL"))
    subcount = purge_level("CRITICAL", keep_days)
    log(
        INFO,
        app="home",
        view="log",
        action="purge",
        status="OK",
        data=f"{subcount} CRITICAL entries removed",
    )
    count += subcount

    # MAX Lines
    keep_entries = int(get_configuration(appname="home", keyname="LOG_MAX_ENTRIES"))
    logcount = CavalibaLog.objects.count()
    if logcount > keep_entries:
        lastitem = CavalibaLog.objects.order_by("-id").first()
        if lastitem:
            lastid = lastitem.id
            cutoff = lastid - keep_entries - 2
            if cutoff > 0:
                subcount = CavalibaLog.objects.filter(id__lt=cutoff).delete()[0]
            else:
                subcount = 0
        log(
            INFO,
            app="home",
            view="log",
            action="purge",
            status="OK",
            data=f"{subcount} MAXLINE entries removed",
        )
        count += subcount

    return count
