#  (c) cavaliba.com - core - settings.py

import os
import sys
from pathlib import Path

from celery.schedules import crontab
from django.contrib.messages import constants as messages
from django.core.management.utils import get_random_secret_key

# -------------------------------------------------------------------
# Cavaliba
# -------------------------------------------------------------------

# dev convention: append "-RC" while this version's migration block
# (app_home/migrator.py::cavaliba_db_update, matched via .startswith("X.Y.Z-RC"))
# is still being iterated on - makes that one block re-run every start regardless
# of DB_VERSION, so there's no need to reset the DB_VERSION registry key by hand
# between edits. Drop "-RC" once the migration is final, before release.
# Caveat: only safe for migration steps that are idempotent (reload_builtin,
# load/save round-trips, etc) - a step with a non-idempotent side effect (e.g.
# unconditionally appending to a list field) must guard itself against running
# twice, since it will run on every start while "-RC" is present.
CAVALIBA_VERSION = "5.4.0"
CAVALIBA_VERSION_DATE = "2026-11-08"

# supported cavctl version
CAVALIBA_CAVCTL_VERSION = "2.6.0"

# apps offered by the Configuration page's top-level app selector (app_home
# "configuration" view/template) - keyname (matches CONFIGURATION_DEFAULT) ->
# {name, icon}. Raw name strings - templates translate at render time (e.g.
# {% translate app.displayname %}). Dict order determines both display order
# and which app opens by default when no appname is given in the URL - keep
# "home" (Global) first.
CONFIGURATION_TOPLEVEL = {
    "home": {"name": "Global", "icon": "fa-globe"},
    "data": {"name": "Data", "icon": "fa-database"},
    "user": {"name": "IAM", "icon": "fa-user-plus"},
    "sirene": {"name": "Notifications", "icon": "fa-sun-o"},
    "cmt": {"name": "CMT", "icon": "fa-heartbeat"},
    "ipam": {"name": "IPAM", "icon": "fa-map-marker"},
}

TRUE_LIST = ("on", "On", "ON", True, "yes", "Yes", "YES", "True", "true", "TRUE", 1, "1")

# app_data:private schema list ordering, by classname: "^name" pins a schema
# first, "$name" pins a schema last (both in the order listed here), "-name"
# hides a schema from the list entirely. Every other visible schema is
# inserted alphabetically (by classname/keyname) between the pinned-first
# and pinned-last groups.
SCHEMA_LIST_ORDER = [
    "^user",
    "^group",
    "^site",
    "^sitegroup",
    "^app",
    "$_enumerate",
    "$_pipeline",
    "$_dataview",
    "$_apikey",
    "$_cmtcheck",
    "$_cmtagent",
    "$sirene_message",
]


# -------------------------------------------------------------------
# Misc
# -------------------------------------------------------------------
# /path/to/source :  /app
BASE_DIR = Path(__file__).resolve().parent.parent

SECRET_KEY = os.environ.get("CAVALIBA_SECRET_KEY", default=get_random_secret_key())
# DEBUG = True
DEBUG = int(os.environ.get("CAVALIBA_DEBUG", default=1))
try:
    ALLOWED_HOSTS = os.environ.get("CAVALIBA_ALLOWED_HOSTS").split(" ")
except Exception:
    ALLOWED_HOSTS = ["*"]

try:
    CSRF_TRUSTED_ORIGINS = os.environ.get("CAVALIBA_CSRF_TRUSTED_ORIGINS").split(" ")
except Exception:
    CSRF_TRUSTED_ORIGINS = [
        "http://localhost:8000",
        "http://192.168.0.11:8000",
        "http://localhost:4180",
    ]


# ENV environnement made available from settings
CAVALIBA_CIPHER_KEY = os.environ.get("CAVALIBA_CIPHER_KEY", None)
CAVALIBA_APIKEY_SECRET = os.environ.get("CAVALIBA_APIKEY_SECRET", None)
CAVALIBA_ADMIN_PASSWORD = os.environ.get("CAVALIBA_ADMIN_PASSWORD", None)
CAVALIBA_AUTH_MODE = os.environ.get("CAVALIBA_AUTH_MODE", "local")
CAVALIBA_FORCE_LOGIN = os.environ.get("CAVALIBA_FORCE_LOGIN", "admin")
CAVALIBA_SMS_LOGIN = os.environ.get("CAVALIBA_SMS_LOGIN", "")
CAVALIBA_SMS_PASSWORD = os.environ.get("CAVALIBA_SMS_PASSWORD", "")
CAVALIBA_SMS_URL = os.environ.get("CAVALIBA_SMS_URL", "")
CAVALIBA_AAA_NOCACHE = os.environ.get("CAVALIBA_AAA_NOCACHE", "no")
CAVALIBA_LAST_LOGIN_MINUTES = int(os.environ.get("CAVALIBA_LAST_LOGIN_MINUTES", "30"))
CAVALIBA_MAX_COMPUTED_USER = int(os.environ.get("CAVALIBA_MAX_COMPUTED_USER", "500"))
CAVALIBA_HTML_FRAMEWORK = os.environ.get("CAVALIBA_HTML_FRAMEWORK", "")  # '' or 'tw4'
CAVALIBA_MAX_IMPORT_ERROR = int(
    os.environ.get("CAVALIBA_MAX_IMPORT_ERROR", "20")
)  # abort a batch import (web Import Tool, async task, /api/load/) once failures exceed this
CAVALIBA_MAX_EXPORT_ERROR = int(
    os.environ.get("CAVALIBA_MAX_EXPORT_ERROR", "20")
)  # abort an export (Exporter tool, async task) once per-instance failures exceed this
CAVALIBA_EXPORT_FILE_TTL_HOURS = int(
    os.environ.get("CAVALIBA_EXPORT_FILE_TTL_HOURS", "24")
)  # lifetime of an async export result file (DataFile.not_after), reaped by filestore_cleanup
CAVALIBA_IPAM_IP_LIST_MAX = int(
    os.environ.get("CAVALIBA_IPAM_IP_LIST_MAX", "256")
)  # ipam_subnet/ipam_vlan detail: ipam_ip rows listed inline, rest offered as a CSV download
CAVALIBA_IPAM_IP_LIST_FILE_MAX = int(
    os.environ.get("CAVALIBA_IPAM_IP_LIST_FILE_MAX", "100000")
)  # hard cap on rows written to that CSV
CAVALIBA_IPAM_IP_LIST_FILE_TTL_HOURS = int(
    os.environ.get("CAVALIBA_IPAM_IP_LIST_FILE_TTL_HOURS", "1")
)  # lifetime of that CSV (DataFile.not_after), reaped by filestore_cleanup

SEARCHBAR_MAX_ANSWER = 100  # top navbar searchbar: max combined results across all stages

# Max SIZE
DATA_UPLOAD_MAX_MEMORY_SIZE = 50000000
FILE_UPLOAD_MAX_MEMORY_SIZE = 50000000

# -------------------------------
# Files / Filestore
# -------------------------------
# global Filer shared beetwen nodes (NFS, ...)
CAVALIBA_FILES = os.environ.get("CAVALIBA_FILES", "./files/")

CAVALIBA_FILESTORE = os.environ.get("CAVALIBA_FILESTORE", Path(CAVALIBA_FILES) / "filestore")
CAVALIBA_EXPORT_FOLDER = os.environ.get("CAVALIBA_EXPORT_FOLDER", Path(CAVALIBA_FILES) / "export")
CAVALIBA_MAIL_FOLDER = os.environ.get("CAVALIBA_MAIL_FOLDER", Path(CAVALIBA_FILES) / "mail")
CAVALIBA_SMS_FOLDER = os.environ.get("CAVALIBA_SMS_FOLDER", Path(CAVALIBA_FILES) / "sms")
CAVALIBA_TEMPLATE_FOLDER = os.environ.get(
    "CAVALIBA_TEMPLATE_FOLDER", Path(CAVALIBA_FILES) / "templates"
)

# encodings offered for CSV export (data export modal, cavaliba CLI --encoding)
SUPPORTED_ENCODING = ["utf-8", "utf-8-sig", "iso-8859-1", "iso-8859-15", "cp1252", "cp850", "ascii"]

# valid --action/force_action override values (/api/load/, /api/rawfile/, cavaliba CLI load)
ACTION_LIST = [
    "create",
    "init",
    "update",
    "delete",
    "enable",
    "disable",
    "append",
    "unappend",
    "noop",
]


# -------------------------------------------------------------------
# Application definition
# -------------------------------------------------------------------
SIRENE_APPS = [
    "app_sirene.apps.AppSireneConfig",
    "app_home.apps.AppHomeConfig",
    "app_user.apps.AppUserConfig",
    "app_data.apps.AppDataConfig",
    "app_cmt.apps.AppCmtConfig",
]

INSTALLED_APPS = SIRENE_APPS + [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "tinymce",
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
    "django.middleware.locale.LocaleMiddleware",
]

ROOT_URLCONF = "core.urls"

# -------------------------------------------------------------------
# django debug toolbar
# -------------------------------------------------------------------

if DEBUG:
    try:
        import debug_toolbar  # noqa
        import socket  # noqa

        INSTALLED_APPS += ["debug_toolbar"]
        MIDDLEWARE.insert(0, "debug_toolbar.middleware.DebugToolbarMiddleware")

        INTERNAL_IPS = ["127.0.0.1", "192.168.0.11", "::1"]
        hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
        for ip in ips:
            prefix = ip[: ip.rfind(".")]
            INTERNAL_IPS += [f"{prefix}.{i}" for i in range(1, 10)]

        # force activation
        # DEBUG_TOOLBAR_CONFIG = {
        #     "SHOW_TOOLBAR_CALLBACK": lambda request: DEBUG,
        # }
        # print("DJANGO DEBUG TOOLBAR: ON")
    except ImportError:
        # print("DJANGO-DEBUG TOOLBAR: OFF")
        pass


# -------------------------------------------------------------------
# TEMPLATES
# -------------------------------------------------------------------

TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        #'DIRS': [ BASE_DIR / 'templates_custom', BASE_DIR / 'templates/'],
        #'DIRS': [ "/app/files/templates/", "/files/templates/", BASE_DIR / 'templates/'],
        "DIRS": [CAVALIBA_TEMPLATE_FOLDER, BASE_DIR / "templates/"],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
                "app_home.context_processor.get_info",  # <-- Add your context processor
            ],
        },
    },
]

WSGI_APPLICATION = "core.wsgi.application"


# -------------------------------------------------------------------
# Database
# -------------------------------------------------------------------

DATABASES = {
    "default": {
        "ENGINE": os.environ.get("CAVALIBA_DB_ENGINE", "django.db.backends.sqlite3"),
        "HOST": os.environ.get("CAVALIBA_DB_HOST", "localhost"),
        "PORT": os.environ.get("CAVALIBA_DB_PORT", 3306),
        "NAME": os.environ.get("CAVALIBA_DB_DATABASE", BASE_DIR / "../db.sqlite3"),
        "USER": os.environ.get("CAVALIBA_DB_USER", "user"),
        "PASSWORD": os.environ.get("CAVALIBA_DB_PASSWORD", "password"),
        "CONN_MAX_AGE": 300,
        "CONN_HEALTH_CHECKS": True,
    }
}

# Default primary key field type
# https://docs.djangoproject.com/en/4.1/ref/settings/#default-auto-field

DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"


# -------------------------------
# Cache
# -------------------------------

MAX_LOCALMEM_CACHE_SIZE = 500

CAVALIBA_CACHE_CONFIGURATION_TIMEOUT = int(
    os.environ.get("CAVALIBA_CACHE_CONFIGURATION_TIMEOUT", default=60)
)
CAVALIBA_CACHE_SCHEMA_TIMEOUT = int(os.environ.get("CAVALIBA_CACHE_SCHEMA_TIMEOUT", default=60))
CAVALIBA_CACHE_INSTANCE_TIMEOUT = int(os.environ.get("CAVALIBA_CACHE_INSTANCE_TIMEOUT", default=60))
CAVALIBA_CACHE_ENUMERATE_TIMEOUT = int(
    os.environ.get("CAVALIBA_CACHE_ENUMERATE_TIMEOUT", default=120)
)
CAVALIBA_CACHE_DATAPOINT_TIMEOUT = int(
    os.environ.get("CAVALIBA_CACHE_DATAPOINT_TIMEOUT", default=60)
)
CAVALIBA_CACHE_IPAM_SUBNET_TIMEOUT = int(
    os.environ.get("CAVALIBA_CACHE_IPAM_SUBNET_TIMEOUT", default=60)
)
CAVALIBA_CACHE_SIDEBAR_TIMEOUT = int(os.environ.get("CAVALIBA_CACHE_SIDEBAR_TIMEOUT", default=120))
CAVALIBA_CACHE_DASHBOARD_TIMEOUT = int(
    os.environ.get("CAVALIBA_CACHE_DASHBOARD_TIMEOUT", default=20)
)

CAVALIBA_CACHE_DEFAULT_URL = os.environ.get("CAVALIBA_CACHE_DEFAULT_URL", default="")
CAVALIBA_CACHE_SESSION_URL = os.environ.get("CAVALIBA_CACHE_SESSION_URL", default="")

if CAVALIBA_CACHE_DEFAULT_URL:
    CACHES = {
        "default": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": CAVALIBA_CACHE_DEFAULT_URL,
            "OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient"},
        },
        "session": {
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": CAVALIBA_CACHE_SESSION_URL or CAVALIBA_CACHE_DEFAULT_URL,
            "OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient"},
        },
    }
else:
    CACHES = {
        "default": {
            "BACKEND": "django.core.cache.backends.db.DatabaseCache",
            "LOCATION": "cavaliba_cache_default",
            "TIMEOUT": 3600,
            "OPTIONS": {
                "MAX_ENTRIES": 10000,
            },
        },
        "session": {
            "BACKEND": "django.core.cache.backends.db.DatabaseCache",
            "LOCATION": "cavaliba_cache_session",
            "TIMEOUT": 3600,
            "OPTIONS": {
                "MAX_ENTRIES": 10000,
            },
        },
    }

# -------------------------------
# Sessions
# -------------------------------

# SESSION_ENGINE = 'django.contrib.sessions.backends.db'
SESSION_CACHE_ALIAS = "session"
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_COOKIE_AGE = int(os.environ.get("CAVALIBA_SESSION_DURATION", default=3600))

SESSION_COOKIE_HTTPONLY = True
SESSION_COOKIE_SAMESITE = "Lax"

# -------------------------------------------------------------------
# Static files (CSS, JavaScript, Images)
# -------------------------------------------------------------------

STATIC_URL = "/static/"

# collectstatic target in Docker mode
STATIC_ROOT = "/static_collect"

# collectstatic source
STATICFILES_DIRS = [
    # highest priority (external)
    BASE_DIR / "files" / "logo",
    # default (internal)
    BASE_DIR / "static",
]

# -------------------------------
# Password validation
# -------------------------------
# https://docs.djangoproject.com/en/4.1/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
    },
    {
        "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
    },
]

# -------------------------------
# Django Login Workflow
# -------------------------------

# which reverse URL to redirect an unauthnticated user in case of noauth view access
CAVALIBA_PUBLIC_REDIRECT = "app_sirene:index"

LOGIN_URL = "/accounts/login"
LOGIN_REDIRECT_URL = "/home/private"


# -------------------------------
# Celery
# -------------------------------

CELERY_BROKER_URL = os.environ.get(
    "CAVALIBA_CELERY_BROKER_URL", default="redis://cavaliba_redis:6379"
)
CELERY_RESULT_BACKEND = os.environ.get(
    "CAVALIBA_CELERY_RESULT_BACKEND", default="redis://cavaliba_redis:6379"
)

# async(*) or sync
CAVALIBA_TASK_CELERY = os.environ.get("CAVALIBA_TASK_CELERY", default="async")
if CAVALIBA_TASK_CELERY == "sync":
    CELERY_TASK_ALWAYS_EAGER = True

# keep settings.LOGGING in workers (Celery replaces root handlers otherwise)
CELERY_WORKER_HIJACK_ROOT_LOGGER = False


CAVALIBA_HOUSEKEEPING_SCHEDULE = os.environ.get("CAVALIBA_HOUSEKEEPING_SCHEDULE", default="22:22")
try:
    tmp = CAVALIBA_HOUSEKEEPING_SCHEDULE.split(":")
    HOUSEKEEPING_HOUR = int(tmp[0])
    HOUSEKEEPING_MINUTE = int(tmp[1])
except Exception as e:
    print("CAVALIBA HOUSEKEEPING CONFIG ERROR: ", e)
    HOUSEKEEPING_HOUR = 22
    HOUSEKEEPING_MINUTE = 22


# CELERY_CONF_UPDATE = {
#     "enable_utc": False,
#     "timezone": "Europe/Paris",
# }
# CELERY_CONF_TIMEZONE = "Europe/Paris"
CELERY_BEAT_SCHEDULE = {
    # "cron1": {
    #     "task": "core.celery.cron1",
    #     #"schedule": crontab(minute="*/1"),
    #     #'schedule': crontab(hour=7, minute=30, day_of_week=1),
    #     "schedule": 3.0,
    #     "schedule": crontab(hour=19, minute=12),
    #     "args": ("hello",)
    # },
    "housekeeping_daily": {
        "task": "app_home.tasks.housekeeping_daily",
        "schedule": crontab(hour=HOUSEKEEPING_HOUR, minute=HOUSEKEEPING_MINUTE),
    },
    "archive_expired_sirene": {
        "task": "app_sirene.notify.archive_expired_sirene",
        "schedule": 60.0,
    },
    # 3.22 - autogroup cache update
    "iam_autogroup_update": {
        "task": "app_data.tasks.task_autogroup_update",
        "schedule": 120.0,
    },
    "cmt_sample_hour": {
        "task": "app_cmt.tasks.task_sample_hour",
        "schedule": 60.0,
    },
    "cmt_sample_day": {
        "task": "app_cmt.tasks.task_sample_day",
        "schedule": 900.0,
    },
    "cmt_cleanup_raw": {
        "task": "app_cmt.tasks.task_cleanup_raw",
        "schedule": 900.0,
    },
    "cmt_cleanup_hour": {
        "task": "app_cmt.tasks.task_cleanup_hour",
        "schedule": 18000.0,
    },
    # 5.4 - telemetry aggregation + raw purge
    "telemetry_aggregate": {
        "task": "app_data.tasks.task_telemetry_aggregate",
        "schedule": 60.0,
    },
    # 5.4 - telemetry object quantity gauges ; on the hour, so every hour bucket gets
    # exactly one sample (an interval beat would drift and leave hours without any)
    "telemetry_sample": {
        "task": "app_data.tasks.task_telemetry_sample",
        "schedule": crontab(minute=5),
    },
}


# -------------------------------
# I18N , TZ
# -------------------------------
# Internationalization
# https://docs.djangoproject.com/en/4.1/topics/i18n/
USE_I18N = True

# LANGUAGE_CODE = 'en-us'
# LANGUAGE_CODE = 'fr-FR'
LANGUAGE_CODE = os.environ.get("CAVALIBA_LANGUAGE_CODE", default="en-us")

USE_TZ = True
# TIME_ZONE = 'UTC'
# TIME_ZONE = 'Europe/Paris'
TIME_ZONE = os.environ.get("CAVALIBA_TIME_ZONE", default="Europe/Paris")

# -------------------------------------------------------------------
# Logging
# -------------------------------------------------------------------
# Three streams, each routed (stdout, file) and levelled on its own:
#   event   retained log2 events (also stored in DB, never level-gated there)
#   debug   transient log2.debug() lines, never stored
#   system  Django, Celery, libraries, plain logging calls (root logger)


def _log_env(name, default=""):
    """Return a CAVALIBA_LOG_* env value, stripped."""
    return os.environ.get(f"CAVALIBA_LOG_{name}", default).strip()


def _log_level(name, default):
    """Return a valid level name from a CAVALIBA_LOG_*_LEVEL env value."""
    value = _log_env(name, default).upper()
    return value if value in ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL") else default


def _log_routes(name, default):
    """Return the destinations ("stdout", "file") listed in a CAVALIBA_LOG_*_TO env value."""
    value = _log_env(name, default).lower()
    return [r for r in ("stdout", "file") if r in value.replace(" ", "").split(",")]


def _log_config_warnings(environ):
    """Return human messages for CAVALIBA_LOG_* values that would be silently ignored or
    route a stream nowhere; logged at startup by AppHomeConfig.ready()."""
    env = {k: v.strip() for k, v in environ.items() if k.startswith("CAVALIBA_LOG_")}
    warnings = []
    for name in ("EVENT", "DEBUG", "SYSTEM"):
        level = env.get(f"CAVALIBA_LOG_{name}_LEVEL", "")
        if level and level.upper() not in ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"):
            warnings.append(f"CAVALIBA_LOG_{name}_LEVEL={level!r} is not a level, default used")
        routes = [r for r in env.get(f"CAVALIBA_LOG_{name}_TO", "").lower().replace(" ", "")
                  .split(",") if r]  # fmt: skip
        unknown = [r for r in routes if r not in ("stdout", "file")]
        if unknown:
            warnings.append(f"CAVALIBA_LOG_{name}_TO: unknown destination(s) {unknown} ignored")
        has_file = env.get("CAVALIBA_LOG_FILE") or (
            name == "DEBUG" and env.get("CAVALIBA_LOG_DEBUG_FILE")
        )
        if "file" in routes and not has_file:
            warnings.append(f"CAVALIBA_LOG_{name}_TO=file but CAVALIBA_LOG_FILE is empty: "
                            "nothing written")  # fmt: skip
    for name, allowed in (("STDOUT", ("text", "json")), ("FILE_FORMAT", ("text", "json")),
                          ("DB", ("yes", "no", "1", "0", "true", "false"))):  # fmt: skip
        value = env.get(f"CAVALIBA_LOG_{name}", "")
        if value and value.lower() not in allowed:
            warnings.append(f"CAVALIBA_LOG_{name}={value!r} not in {allowed}, default used")
    return warnings


CAVALIBA_LOG_CONFIG_WARNINGS = _log_config_warnings(os.environ)
CAVALIBA_LOG_DB = _log_env("DB", "yes").lower() in ("yes", "1", "true")
CAVALIBA_LOG_STDOUT = "json" if _log_env("STDOUT", "text").lower() == "json" else "text"
CAVALIBA_LOG_FILE = _log_env("FILE", "")
CAVALIBA_LOG_FILE_FORMAT = "text" if _log_env("FILE_FORMAT", "json").lower() == "text" else "json"
CAVALIBA_LOG_DEBUG_FILE = _log_env("DEBUG_FILE", "")
CAVALIBA_LOG_DEBUG_MODULES = [
    m for m in _log_env("DEBUG_MODULES", "").replace(" ", "").split(",") if m
]

_LOG_OFF = 100  # above CRITICAL: a stream routed nowhere costs nothing


def _log_handlers(routes, file_handler="file"):
    """Map routes to handler names; NullHandler keeps logging's lastResort off."""
    names = []
    if "stdout" in routes:
        names.append("stdout")
    if "file" in routes and (CAVALIBA_LOG_FILE or file_handler == "debug_file"):
        names.append(file_handler)
    return names or ["null"]


# manage.py test: events still stored in DB, not exported unless CAVALIBA_LOG_EVENT_TO is set
_TESTING = len(sys.argv) > 1 and sys.argv[1] == "test"
_event_routes = _log_routes("EVENT_TO", "" if _TESTING else "stdout")
_debug_routes = _log_routes("DEBUG_TO", "")
_system_routes = _log_routes("SYSTEM_TO", "" if _TESTING else "stdout")
_debug_level = _log_level("DEBUG_LEVEL", "DEBUG")

LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "formatters": {
        "text": {"()": "app_home.logformat.TextFormatter"},
        "json": {"()": "app_home.logformat.EcsJsonFormatter"},
    },
    "handlers": {
        "null": {"class": "logging.NullHandler"},
        "stdout": {
            "class": "logging.StreamHandler",
            "stream": "ext://sys.stdout",
            "formatter": CAVALIBA_LOG_STDOUT,
        },
    },
    "loggers": {
        "cavaliba.event": {
            "handlers": _log_handlers(_event_routes),
            "level": _log_level("EVENT_LEVEL", "INFO") if _event_routes else _LOG_OFF,
            "propagate": False,
        },
        "cavaliba.debug": {
            "handlers": _log_handlers(
                _debug_routes, "debug_file" if CAVALIBA_LOG_DEBUG_FILE else "file"
            ),
            "level": _debug_level if _debug_routes and not CAVALIBA_LOG_DEBUG_MODULES else _LOG_OFF,
            "propagate": False,
        },
        # drop Django's default console handler: records reach root (system stream) once
        "django": {"handlers": [], "level": "INFO", "propagate": True},
        "django.db.backends": {"level": "WARNING"},
        "celery": {"level": "INFO"},
    },
    "root": {
        "handlers": _log_handlers(_system_routes),
        "level": _log_level("SYSTEM_LEVEL", "INFO"),
    },
}

if CAVALIBA_LOG_FILE:
    LOGGING["handlers"]["file"] = {
        "class": "logging.handlers.WatchedFileHandler",
        "filename": CAVALIBA_LOG_FILE,
        "formatter": CAVALIBA_LOG_FILE_FORMAT,
    }

if CAVALIBA_LOG_DEBUG_FILE:
    LOGGING["handlers"]["debug_file"] = {
        "class": "logging.handlers.WatchedFileHandler",
        "filename": CAVALIBA_LOG_DEBUG_FILE,
        "formatter": CAVALIBA_LOG_FILE_FORMAT,
    }

# debug for selected modules only (children inherit cavaliba.debug's handlers)
if _debug_routes:
    for _module in CAVALIBA_LOG_DEBUG_MODULES:
        LOGGING["loggers"][f"cavaliba.debug.{_module}"] = {"level": _debug_level}

# -------------------------------------------------------------------
# Flash message
# -------------------------------------------------------------------

# from django.contrib.messages import constants as messages

MESSAGE_TAGS = {
    messages.DEBUG: "alert-info",
    messages.INFO: "alert-info",
    messages.SUCCESS: "alert-success",
    messages.WARNING: "alert-warning",
    messages.ERROR: "alert-danger",
}

# -------------------------------------------------------------------
# translation files
# -------------------------------------------------------------------
# LOCALE_PATHS = [
#     BASE_DIR / "locale",
# ]

# -------------------------------------------------------------------
# fixture
# -------------------------------------------------------------------
FIXTURE_DIRS = [
    BASE_DIR / "fixture",
]

# -------------------------------------------------------------------
# TinyMCE
# -------------------------------------------------------------------
# TINYMCE_JS_URL (default: settings.STATIC_URL + 'tinymce/tinymce.min.js')
# The URL of the TinyMCE javascript file:
# TINYMCE_JS_URL = os.path.join(STATIC_URL, "path/to/tiny_mce/tiny_mce.js")

TINYMCE_DEFAULT_CONFIG = {
    "theme": "silver",
    "height": 500,
    "menubar": False,
    "plugins": "advlist,autolink,lists,link,image,charmap,print,preview,anchor,"
    "searchreplace,visualblocks,code,fullscreen,insertdatetime,media,table,paste,"
    "code,help,wordcount",
    "toolbar": "undo redo | formatselect | link |"
    "bold italic backcolor | alignleft aligncenter "
    "alignright alignjustify | bullist numlist outdent indent | "
    "removeformat | code | preview | help",
    "relative_urls": 0,
    "remove_script_host": 0,
    # "setup": "function (editor) {editor.on('change', function () {tinymce.triggerSave();});}",
}

TINYMCE_COMPRESSOR = False
TINYMCE_SPELLCHECKER = False
TINYMCE_FILEBROWSER = False

# -------------------------------------------------------------------
# SIRENE EMAIL GENERAL SETUP
# -------------------------------------------------------------------

EMAIL_HOST = os.environ.get("CAVALIBA_EMAIL_HOST", default="localhost")
EMAIL_PORT = int(os.environ.get("CAVALIBA_EMAIL_PORT", default=25))
EMAIL_HOST_USER = os.environ.get("CAVALIBA_EMAIL_USER", "")
EMAIL_HOST_PASSWORD = os.environ.get("CAVALIBA_EMAIL_PASSWORD", "")

if EMAIL_PORT == 465:
    EMAIL_USE_SSL = True

if EMAIL_PORT == 587:
    EMAIL_USE_TLS = True


# -------------------------------------------------------------------
# in test mode (unittest)
# -------------------------------------------------------------------
# activate if no fixtures in tests
TEST_RUNNER = "core.test_runner.CavalibaTestRunner"


# *-*-*-*
