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

import sys

from django.conf import settings

import app_home.cache as cache

from .configuration_default import CONFIGURATION_DEFAULT
from .configuration_form import (
    AppDataConfigurationForm,
    AppHomeConfigurationForm,
    AppIpamConfigurationForm,
    AppSireneConfigurationForm,
    AppStatusConfigurationForm,
    AppUserConfigurationForm,
)
from .models import CavalibaConfiguration

# --------------------------------------------
# cache / get / set
# --------------------------------------------


def load_configuration_cache():

    cache.cache_configuration = {}

    # first, load default
    for appname, appconfig in CONFIGURATION_DEFAULT.items():
        cache.cache_configuration[appname] = {}
        for k, v in appconfig.items():
            cache.cache_configuration[appname][k] = v

    # then, load from db
    dbconf = CavalibaConfiguration.objects.all()
    for item in dbconf:
        if item.appname not in cache.cache_configuration:
            cache.cache_configuration[item.appname] = {}
        cache.cache_configuration[item.appname][item.keyname] = item.value

    # NEXT: store in faster redis cache


def get_configuration(appname="home", keyname=None):

    resp_env = None

    if appname == "env":
        resp_env = getattr(settings, keyname, None)

    if resp_env:
        return resp_env

    if appname in cache.cache_configuration:
        if keyname in cache.cache_configuration[appname]:
            return cache.cache_configuration[appname][keyname]

    load_configuration_cache()

    if appname in cache.cache_configuration:
        if keyname in cache.cache_configuration[appname]:
            return cache.cache_configuration[appname][keyname]

    return


def set_configuration(
    init_only=False, appname=None, keyname=None, description=None, value=None, order=None, page=None
):

    # init : if True, only create non-existing entries
    if not appname:
        return
    if not keyname:
        return

    dbentry = CavalibaConfiguration.objects.filter(appname=appname, keyname=keyname).first()

    # init only ?
    if init_only:
        if dbentry:
            return

    # create if missing
    if not dbentry:
        dbentry = CavalibaConfiguration()

    # update
    dbentry.appname = appname
    dbentry.keyname = keyname
    dbentry.description = description
    dbentry.page = page
    dbentry.order = order
    dbentry.value = value
    dbentry.save()

    return dbentry


# --------------------------------------------
# CLI
# --------------------------------------------
def conf_list():

    return CavalibaConfiguration.objects.all().order_by("appname")


# --------------------------------------------
# Form
# --------------------------------------------


def get_post_form(request, appname=None):

    if not appname:
        return

    load_configuration_cache()

    if appname not in cache.cache_configuration:
        return

    if appname == "sirene":
        form = AppSireneConfigurationForm(request.POST)
    elif appname == "home":
        form = AppHomeConfigurationForm(request.POST)
    elif appname == "user":
        form = AppUserConfigurationForm(request.POST)
    elif appname == "data":
        form = AppDataConfigurationForm(request.POST)
    elif appname == "status":
        form = AppStatusConfigurationForm(request.POST)
    elif appname == "ipam":
        form = AppIpamConfigurationForm(request.POST)
    else:
        form = None

    return form


def get_initial_form(appname=None):

    if not appname:
        return

    load_configuration_cache()

    if appname not in cache.cache_configuration:
        return

    initial = {}
    for k, v in cache.cache_configuration[appname].items():
        initial[k] = v

    if appname == "sirene":
        form = AppSireneConfigurationForm(initial=initial)
    elif appname == "home":
        form = AppHomeConfigurationForm(initial=initial)
    elif appname == "user":
        form = AppUserConfigurationForm(initial=initial)
    elif appname == "data":
        form = AppDataConfigurationForm(initial=initial)
    elif appname == "status":
        form = AppStatusConfigurationForm(initial=initial)
    elif appname == "ipam":
        form = AppIpamConfigurationForm(initial=initial)
    else:
        form = None
    return form


def save_form(form, appname=None):

    if not appname:
        return

    load_configuration_cache()

    if appname not in cache.cache_configuration:
        return

    if appname not in CONFIGURATION_DEFAULT:
        return

    appconfig = CONFIGURATION_DEFAULT[appname]

    for k, v in form.cleaned_data.items():
        if k in appconfig:
            dbentry = CavalibaConfiguration.objects.filter(appname=appname, keyname=k).first()
            if not dbentry:
                dbentry = CavalibaConfiguration()
                dbentry.appname = appname
                dbentry.keyname = k

            dbentry.value = v
            dbentry.save()

    # perform a reload to populate cache
    load_configuration_cache()
    cache.cache2_configuration.clear()


# -------------------------------------------------------------------
# commands
# -------------------------------------------------------------------


def sync_configuration(verbose=False):
    """update configuration - purge / add new default conf entries"""

    r1 = purge_configuration_default(verbose=verbose)
    if verbose:
        sys.stdout.write(f"configuration: {r1} orphans purged\n\n")

    r2 = add_configuration_default(verbose=verbose)
    if verbose:
        sys.stdout.write(f"configuration: {r2} new entries created\n\n")


# no direct call
def add_configuration_default(verbose=True):
    # add new/missing configuration entries with default values

    count = 0

    for appname, appconfig in CONFIGURATION_DEFAULT.items():
        # env objects from env, not from DB
        if appname == "env":
            continue

        for keyname, value in appconfig.items():
            dbentry = set_configuration(
                init_only=True,
                appname=appname,
                keyname=keyname,
                description="",
                value=value,
                order=100,
                page="",
            )
            if dbentry:
                count += 1
                if verbose:
                    sys.stdout.write(f"ADDED - {appname} - {keyname} - {value}\n")
            else:
                if verbose:
                    sys.stdout.write(f"NO CHANGE - {appname} - {keyname} - {value}\n")

    return count


# no direct call
def purge_configuration_default(verbose=True):
    """remove orphans conf entries"""

    count = 0

    dbentries = CavalibaConfiguration.objects.all()

    for dbentry in dbentries:
        appname = dbentry.appname
        keyname = dbentry.keyname
        value = dbentry.value

        # patch: env entries mustn't be in DB
        if dbentry.appname == "env":
            dbentry.delete()
            count += 1
            if verbose:
                sys.stdout.write(f"DELETE - {appname} - {keyname} - {value}\n")

        # app not existing
        elif dbentry.appname not in CONFIGURATION_DEFAULT:
            dbentry.delete()
            count += 1
            if verbose:
                sys.stdout.write(f"DELETE - {appname} - {keyname} - {value}\n")

        # entry for app not existing
        else:
            if dbentry.keyname not in CONFIGURATION_DEFAULT[dbentry.appname]:
                dbentry.delete()
                count += 1
                if verbose:
                    sys.stdout.write(f"DELETE - {appname} - {keyname} - {value}\n")
            else:
                if verbose:
                    sys.stdout.write(f"NO CHANGE - {appname} - {keyname} - {value}\n")
    return count
