"""
Runtime feature flags for the vision pipeline.

Only one flag now — the master vision switch. Runtime overrides live in
Redis under ``mulita:flags:<name>``; an unset key falls back to the
YAML default.
"""
from __future__ import annotations

import logging
from typing import Optional

import redis

from app.config import settings

logger = logging.getLogger(__name__)


FLAG_VISION_ENABLED = 'vision.enabled'

ALL_FLAGS = (FLAG_VISION_ENABLED,)

_VISION_QUEUE = 'vision'

_REDIS: Optional[redis.Redis] = None


def _redis() -> Optional[redis.Redis]:
    global _REDIS
    if _REDIS is None:
        try:
            _REDIS = redis.Redis.from_url(
                settings.celery_broker_url, decode_responses=True
            )
            _REDIS.ping()
        except Exception as e:
            logger.warning(f"feature_flags: Redis unavailable, using YAML defaults ({e})")
            _REDIS = None
    return _REDIS


def _yaml_default(name: str) -> bool:
    if name == FLAG_VISION_ENABLED:
        return bool(settings.vision.enabled)
    raise ValueError(f"Unknown feature flag: {name!r}")


def _redis_key(name: str) -> str:
    return f"mulita:flags:{name}"


def is_enabled(name: str) -> bool:
    r = _redis()
    if r is not None:
        try:
            raw = r.get(_redis_key(name))
            if raw is not None:
                return raw.lower() == 'true'
        except Exception as e:
            logger.warning(f"feature_flags: Redis read failed for {name} ({e})")
    return _yaml_default(name)


def set_flag(name: str, value: bool) -> None:
    if name not in ALL_FLAGS:
        raise ValueError(f"Unknown feature flag: {name!r}")
    r = _redis()
    if r is None:
        raise RuntimeError("Redis unavailable; cannot update feature flags")
    r.set(_redis_key(name), 'true' if value else 'false')
    _apply_worker_side_effects(name)


def reset_flag(name: str) -> None:
    if name not in ALL_FLAGS:
        raise ValueError(f"Unknown feature flag: {name!r}")
    r = _redis()
    if r is None:
        raise RuntimeError("Redis unavailable; cannot reset feature flags")
    r.delete(_redis_key(name))
    _apply_worker_side_effects(name)


def _apply_worker_side_effects(name: str) -> None:
    """Attach or detach the vision consumer and purge queued work when
    the master flag flips. Best-effort — state is already persisted."""
    if name != FLAG_VISION_ENABLED:
        return
    try:
        from app.tasks.celery import celery_app
    except Exception as e:
        logger.warning(f"feature_flags: celery app unavailable for side effects ({e})")
        return

    try:
        if is_enabled(FLAG_VISION_ENABLED):
            celery_app.control.add_consumer(_VISION_QUEUE, reply=False)
            logger.info("feature_flags: vision re-enabled; consumer added")
        else:
            celery_app.control.cancel_consumer(_VISION_QUEUE, reply=False)
            _purge_queue(_VISION_QUEUE)
            logger.info("feature_flags: vision disabled; consumer cancelled and queue purged")
    except Exception as e:
        logger.warning(f"feature_flags: worker side effects failed: {e}")


def _purge_queue(queue: str) -> int:
    r = _redis()
    if r is None:
        return 0
    try:
        return int(r.delete(queue) or 0)
    except Exception as e:
        logger.warning(f"feature_flags: purge {queue} failed: {e}")
        return 0


def snapshot() -> dict[str, dict[str, object]]:
    r = _redis()
    out: dict[str, dict[str, object]] = {}
    for name in ALL_FLAGS:
        default = _yaml_default(name)
        override = None
        if r is not None:
            try:
                raw = r.get(_redis_key(name))
                if raw is not None:
                    override = raw.lower() == 'true'
            except Exception:
                pass
        out[name] = {
            'effective': override if override is not None else default,
            'default': default,
            'overridden': override is not None,
        }
    return out
