# Copyright (c) 2026 MergeGuide, Inc. All rights reserved.
# SPDX-License-Identifier: Proprietary
"""Cache metrics for CloudWatch.

This module provides functionality to emit cache hit/miss metrics
to CloudWatch for monitoring cache effectiveness.

Metrics Namespace: MergeGuide/Cache

Metrics Published:
- CacheHits: Number of cache hits per cache name
- CacheMisses: Number of cache misses per cache name
- CacheHitRatio: Ratio of hits to total requests (0.0-1.0)
- CacheSize: Current number of entries in cache

Dimensions:
- CacheName: Name of the cache (policy, org, install)
- Environment: Deployment environment (dev, test, prod)

Example usage:
    >>> from mergeguide.cache.metrics import emit_cache_metrics, emit_all_cache_metrics
    >>> from mergeguide.cache import get_all_stats
    >>>
    >>> # Emit metrics for all caches
    >>> emit_all_cache_metrics()
    >>>
    >>> # Or emit for specific cache
    >>> emit_cache_metrics("policy", hits=100, misses=20, size=50)
"""

from __future__ import annotations

import logging
import os
from typing import Any

logger = logging.getLogger(__name__)

# Environment for metric dimensions
ENVIRONMENT = os.environ.get("ENVIRONMENT", "dev")
METRICS_NAMESPACE = "MergeGuide/Cache"

# Flag to disable metrics (for testing or local dev)
METRICS_DISABLED = os.environ.get("MERGEGUIDE_METRICS_DISABLED", "").lower() in (
    "true",
    "1",
    "yes",
)

# Cache the CloudWatch client for reuse
_cloudwatch_client: Any | None = None


def _get_cloudwatch_client() -> Any:
    """Get or create CloudWatch client (lazy initialization)."""
    global _cloudwatch_client
    if _cloudwatch_client is None:
        import boto3

        _cloudwatch_client = boto3.client("cloudwatch")
    return _cloudwatch_client


def emit_cache_metrics(
    cache_name: str,
    hits: int,
    misses: int,
    size: int,
    hit_ratio: float | None = None,
) -> None:
    """Emit cache hit/miss metrics to CloudWatch.

    Args:
        cache_name: Name of the cache (e.g., "policy", "org", "install")
        hits: Number of cache hits since last emission
        misses: Number of cache misses since last emission
        size: Current number of entries in the cache
        hit_ratio: Pre-calculated hit ratio (if None, calculated from hits/misses)
    """
    if METRICS_DISABLED:
        logger.debug(f"Metrics disabled, skipping emit for {cache_name}")
        return

    try:
        cloudwatch = _get_cloudwatch_client()

        # Calculate hit ratio if not provided
        if hit_ratio is None:
            total = hits + misses
            hit_ratio = hits / total if total > 0 else 0.0

        # Build metric data
        dimensions = [
            {"Name": "CacheName", "Value": cache_name},
            {"Name": "Environment", "Value": ENVIRONMENT},
        ]

        metric_data = [
            {
                "MetricName": "CacheHits",
                "Dimensions": dimensions,
                "Value": float(hits),
                "Unit": "Count",
            },
            {
                "MetricName": "CacheMisses",
                "Dimensions": dimensions,
                "Value": float(misses),
                "Unit": "Count",
            },
            {
                "MetricName": "CacheHitRatio",
                "Dimensions": dimensions,
                "Value": hit_ratio,
                "Unit": "None",
            },
            {
                "MetricName": "CacheSize",
                "Dimensions": dimensions,
                "Value": float(size),
                "Unit": "Count",
            },
        ]

        cloudwatch.put_metric_data(
            Namespace=METRICS_NAMESPACE,
            MetricData=metric_data,
        )

        logger.debug(
            f"Emitted cache metrics for {cache_name}: "
            f"hits={hits}, misses={misses}, ratio={hit_ratio:.2%}, size={size}"
        )

    except Exception as e:
        # Don't fail the request if metrics emission fails
        logger.warning(f"Failed to emit cache metrics for {cache_name}: {e}")


def emit_all_cache_metrics() -> None:
    """Emit metrics for all cache instances.

    Collects stats from all cache instances (policy, org, install)
    and emits them to CloudWatch.
    """
    from mergeguide.cache import get_all_stats

    stats = get_all_stats()

    for cache_name, cache_stats in stats.items():
        emit_cache_metrics(
            cache_name=cache_name,
            hits=cache_stats["hits"],
            misses=cache_stats["misses"],
            size=cache_stats["size"],
            hit_ratio=cache_stats.get("hit_ratio"),
        )


def reset_all_cache_stats() -> None:
    """Reset hit/miss counters on all caches after emitting metrics.

    Call this after emitting metrics to start fresh counters
    for the next reporting period.
    """
    from mergeguide.cache import get_install_cache, get_org_cache, get_policy_cache

    get_policy_cache().reset_stats()
    get_org_cache().reset_stats()
    get_install_cache().reset_stats()

    logger.debug("Reset all cache statistics")
