"""
Dynamic server-side values for API arguments (optionally cached)

When any function here is uses as default value, CLI usage will show
the *name* of the function as server-side value, so they should be
reasonable named.
"""
import functools
import inspect
import logging
import os.path
import sys

from mini_buildd import config, daemon, events, util

LOG = logging.getLogger(__name__)


def _diststrs(repo_status, **suite_option_kwargs):
    diststrs = []
    for r in util.models().Repository.objects.filter(status__gte=repo_status):
        diststrs += r.mbd_get_diststrs(suiteoption_filter=suite_option_kwargs)
    return diststrs


@functools.cache
def all_repositories():
    return [r.identity for r in util.models().Repository.objects.all()]


@functools.cache
def all_codenames():
    return set(util.models().mbd_icodenames())


@functools.cache
def all_suites():
    return [s.name for s in util.models().Suite.objects.all()]


@functools.cache
def all_chroots():
    return [c.mbd_key() for c in util.models().Chroot.objects.all()]


@functools.cache
def all_remotes():
    return [r.http for r in util.models().Remote.objects.all()]


@functools.cache
def all_cronjobs():
    return {j.id() for j in daemon.get().crontab.jobs}


@functools.cache
def prepared_distributions():
    return _diststrs(util.models().Repository.STATUS_PREPARED)


@functools.cache
def active_distributions():
    return _diststrs(util.models().Repository.STATUS_ACTIVE)


@functools.cache
def active_uploadable_distributions():
    return _diststrs(util.models().Repository.STATUS_ACTIVE, uploadable=True)


@functools.cache
def active_experimental_distributions():
    return [d for d in _diststrs(util.models().Repository.STATUS_ACTIVE, experimental=True) if d.endswith("experimental")]


@functools.cache
def migratable_distributions():
    return _diststrs(util.models().Repository.STATUS_PREPARED, migrates_to__isnull=False)


@functools.cache
def active_keyring_distributions():
    return _diststrs(util.models().Repository.STATUS_ACTIVE, build_keyring_package=True)


def current_builds():
    return daemon.get().builder.builds.keys()


def last_sources():
    return util.attempt(lambda: sorted({event.source for event in daemon.get().events if event.source}), retval_on_failure=[])


def last_failed_bkeys():
    return util.attempt(lambda: sorted({event.extra.get("bkey") for event in daemon.get().events if event.type == events.Type.FAILED and event.extra}), retval_on_failure=[])


def default_identity():
    return config.default_identity()


def default_ftp_endpoint():
    return config.default_ftp_endpoint()


def default_chroot_backend():
    return "Dir"


def default_debmirror_destination():
    return f"{os.path.expanduser('~')}/debmirror/{{}}"


def cache_clear():
    LOG.debug("Clearing values cache...")
    for n, f in inspect.getmembers(sys.modules[__name__]):
        if callable(f) and (clear := getattr(f, "cache_clear", None)) is not None:
            LOG.debug("Clearing values cache for: %s", n)
            clear()
