"""Auto-configuration of Celery settings for monitoring.

The three critical flags that Sluice needs are all False by default in Celery:

- ``worker_send_task_events``: enables the task event stream
- ``task_send_sent_event``: tracks task dispatch from the client side
- ``task_track_started``: tracks when execution begins

This module auto-enables them and warns (never fails) if the user has
explicitly disabled any of them. We never touch ``worker_hijack_root_logger``
— overriding logging config is the user's domain.
"""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from celery import Celery

logger = logging.getLogger("sluice")

# The three flags that must be True for Sluice to receive full event data.
_CRITICAL_FLAGS: dict[str, bool] = {
    "worker_send_task_events": True,
    "task_send_sent_event": True,
    "task_track_started": True,
}

# Flags we must NEVER modify — they belong to the user.
_NEVER_TOUCH: frozenset[str] = frozenset({"worker_hijack_root_logger"})


def auto_configure(app: Celery) -> list[str]:
    """Set the three critical monitoring flags on a Celery app.

    Returns a list of human-readable messages describing what was changed
    or warned about. Each message is also logged.

    Rules:
    - If a flag is not explicitly set by the user, we set it to True and
      log an INFO message.
    - If a flag was explicitly set to False by the user, we warn but do NOT
      override it. The user's intent is respected.
    - We never touch ``worker_hijack_root_logger``.
    """
    messages: list[str] = []

    for flag, desired in _CRITICAL_FLAGS.items():
        if flag in _NEVER_TOUCH:  # pragma: no cover — defensive
            continue

        current = getattr(app.conf, flag, None)

        if current is desired:
            # Already correct — nothing to do.
            continue

        if _is_explicitly_set(app, flag) and current is False:
            # User explicitly disabled this flag. Warn, don't override.
            msg = (
                f"[sluice] Warning: {flag} is explicitly set to False. "
                f"Sluice needs this enabled for full monitoring coverage. "
                f"See: https://docs.sluice.sh/config/celery-flags"
            )
            logger.warning(msg)
            messages.append(msg)
        else:
            # Flag is unset or defaulted — safe to enable.
            setattr(app.conf, flag, desired)
            msg = f"[sluice] Enabled {flag}=True"
            logger.info(msg)
            messages.append(msg)

    return messages


def _is_explicitly_set(app: Celery, flag: str) -> bool:
    """Check whether a Celery config flag was explicitly set by the user.

    Celery stores user-supplied overrides in ``app.conf._order``. If the
    flag is there, the user (or their config) set it explicitly.

    Falls back to checking ``app.conf.changes`` for older Celery versions,
    and finally checks ``app.conf.table`` (explicit user config dict).
    """
    # app.conf._order is a list of keys in the order they were set.
    # Present since Celery 4.x.
    order: list[str] | None = getattr(app.conf, "_order", None)
    if order is not None:
        return flag in order

    # Fallback: check changes dict (Celery stores user overrides here).
    changes: dict[str, object] | None = getattr(app.conf, "changes", None)
    if changes is not None:
        return flag in changes

    # Last resort: check if the value differs from Celery's known default.
    # All three critical flags default to False.
    current = getattr(app.conf, flag, None)
    return current is not None and current is not False


def is_django_project() -> bool:
    """Detect whether the current process is running inside a Django project.

    We check for ``DJANGO_SETTINGS_MODULE`` env var OR the ``django``
    package being importable with settings configured.
    """
    import os

    if os.environ.get("DJANGO_SETTINGS_MODULE"):
        return True

    try:
        import django  # noqa: F401
        from django.conf import settings

        return bool(settings.configured)
    except ImportError:
        return False
    except Exception:
        logger.debug("[sluice] Unexpected error checking for Django.", exc_info=True)
        return False
