"""In-memory TTL cache for expensive scoring and metrics calculations.

The cache is a simple dict with timestamps. It is invalidated when tests
are validated, scores change, or an explicit ``invalidate`` call is made.

Thread-safe: each worker process has its own dict, and the TTL ensures
stale data does not persist longer than ``CACHE_TTL`` seconds.
"""

# Import time
import time

# Import Any, Optional from typing
from typing import Any, Optional

# Import Session from sqlalchemy.orm
from sqlalchemy.orm import Session

# Assign CACHE_TTL = 300  # 5 minutes
CACHE_TTL = 300  # 5 minutes

# Assign _cache = {}
_cache: dict[str, dict[str, Any]] = {}


# Define function get
def get(key: str) -> Optional[Any]:  # noqa: ANN401  # generic cache returns whatever was stored
    """Return cached value if present and not expired, else None."""
    # Assign entry = _cache.get(key)
    entry = _cache.get(key)
    # Check: entry is None
    if entry is None:
        # Return None
        return None
    # Check: time.time() - entry["ts"] > CACHE_TTL
    if time.time() - entry["ts"] > CACHE_TTL:
        # Call _cache.pop()
        _cache.pop(key, None)
        # Return None
        return None
    # Return entry["data"]
    return entry["data"]


# Define function put
def put(key: str, data: Any) -> None:  # noqa: ANN401  # generic cache accepts any serialisable value
    """Store *data* under *key* with the current timestamp."""
    # Assign _cache[key] = {"data": data, "ts": time.time()}
    _cache[key] = {"data": data, "ts": time.time()}


# Define function invalidate
def invalidate(key: Optional[str] = None) -> None:
    """Remove one key or clear the whole cache."""
    # Check: key is None
    if key is None:
        # Call _cache.clear()
        _cache.clear()
    # Fallback: handle remaining cases
    else:
        # Call _cache.pop()
        _cache.pop(key, None)


# ── High-level helpers ────────────────────────────────────────────────


def get_organization_score_cached(db: Session) -> dict:
    """Cached wrapper around ``calculate_organization_score``."""
    # Import calculate_organization_score from app.services.scoring_service
    from app.services.scoring_service import calculate_organization_score

    # Assign cached = get("org_score")
    cached = get("org_score")
    # Check: cached is not None
    if cached is not None:
        # Return cached
        return cached

    # Assign result = calculate_organization_score(db)
    result = calculate_organization_score(db)
    # Call put()
    put("org_score", result)
    # Return result
    return result


# Define function get_operational_metrics_cached
def get_operational_metrics_cached(db: Session) -> dict:
    """Cached wrapper around operational metrics (MTTD, MTTR, efficacy)."""
    # Import  from app.services.operational_metrics_service
    from app.services.operational_metrics_service import (
        calculate_alert_fidelity,
        calculate_coverage_velocity,
        calculate_detection_efficacy,
        calculate_mttd,
        calculate_mttr,
        calculate_rejection_rate,
        calculate_validation_throughput,
    )

    # Assign cached = get("op_metrics")
    cached = get("op_metrics")
    # Check: cached is not None
    if cached is not None:
        # Return cached
        return cached

    # Assign result = {
    result = {
        # Literal argument value
        "mttd": calculate_mttd(db),
        # Literal argument value
        "mttr": calculate_mttr(db),
        # Literal argument value
        "detection_efficacy": calculate_detection_efficacy(db),
        # Literal argument value
        "alert_fidelity": calculate_alert_fidelity(db),
        # Literal argument value
        "coverage_velocity": calculate_coverage_velocity(db),
        # Literal argument value
        "validation_throughput": calculate_validation_throughput(db),
        # Literal argument value
        "rejection_rate": calculate_rejection_rate(db),
    }
    # Call put()
    put("op_metrics", result)
    # Return result
    return result
