"""
Fix Runtime Configuration.

Settings for the fix runtime including caching, refresh intervals,
and fix application behavior.
"""

from __future__ import annotations

import os
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional


@dataclass
class FixRuntimeConfig:
    """
    Configuration for the fix runtime.

    Controls how fixes are loaded, cached, and applied.
    """

    # API settings
    api_endpoint: str = ""
    api_key: Optional[str] = None
    project_id: Optional[str] = None

    # Caching
    cache_enabled: bool = True
    cache_ttl_seconds: int = 300  # 5 minutes
    cache_max_entries: int = 1000

    # Refresh
    auto_refresh: bool = True
    refresh_interval_seconds: int = 60  # 1 minute

    # Fix application
    enabled: bool = True
    dry_run: bool = False  # Log but don't apply fixes
    max_retries: int = 3  # Max retry fix attempts

    # A/B testing
    ab_testing_enabled: bool = True
    track_effectiveness: bool = True

    # Performance
    timeout_ms: int = 1000  # Max time for fix lookup/application

    # Debugging
    debug: bool = False

    @classmethod
    def from_env(cls) -> "FixRuntimeConfig":
        """Create configuration from environment variables."""

        def _safe_int(env_var: str, default: int) -> int:
            """Parse env var as int, returning default on invalid values."""
            raw = os.getenv(env_var)
            if raw is None:
                return default
            try:
                return int(raw)
            except (ValueError, TypeError):
                return default

        return cls(
            api_endpoint=os.getenv("RISICARE_ENDPOINT", "https://app.risicare.ai"),
            api_key=os.getenv("RISICARE_API_KEY"),
            project_id=os.getenv("RISICARE_PROJECT_ID"),
            cache_enabled=os.getenv("RISICARE_FIX_CACHE", "true").lower() == "true",
            cache_ttl_seconds=_safe_int("RISICARE_FIX_CACHE_TTL", 300),
            auto_refresh=os.getenv("RISICARE_FIX_AUTO_REFRESH", "true").lower() == "true",
            refresh_interval_seconds=_safe_int("RISICARE_FIX_REFRESH_INTERVAL", 60),
            enabled=os.getenv("RISICARE_FIX_ENABLED", "true").lower() == "true",
            dry_run=os.getenv("RISICARE_FIX_DRY_RUN", "false").lower() == "true",
            ab_testing_enabled=os.getenv("RISICARE_AB_TESTING", "true").lower() == "true",
            track_effectiveness=os.getenv("RISICARE_TRACK_EFFECTIVENESS", "true").lower() == "true",
            debug=os.getenv("RISICARE_DEBUG", "false").lower() == "true",
        )


@dataclass
class ActiveFix:
    """
    An active fix loaded from the API.

    Represents a fix configuration that should be applied
    when matching error patterns are encountered.
    """

    fix_id: str
    deployment_id: str
    error_code: str  # Pattern to match (e.g., TOOL.EXECUTION.TIMEOUT)
    fix_type: str  # prompt, parameter, tool, retry, fallback, guard, routing
    config: Dict[str, Any] = field(default_factory=dict)
    traffic_percentage: int = 100  # For A/B testing
    version: int = 1

    def matches_error(self, error_code: str) -> bool:
        """
        Check if this fix matches the given error code.

        Supports exact match and prefix matching:
        - "TOOL.EXECUTION.TIMEOUT" matches "TOOL.EXECUTION.TIMEOUT"
        - "TOOL.EXECUTION.*" matches "TOOL.EXECUTION.TIMEOUT", "TOOL.EXECUTION.FAILURE", etc.
        - "TOOL.*" matches any TOOL error
        """
        if self.error_code == error_code:
            return True

        # Wildcard matching
        if self.error_code.endswith("*"):
            prefix = self.error_code[:-1]
            return error_code.startswith(prefix)

        return False

    def should_apply(self, session_hash: int) -> bool:
        """
        Determine if fix should be applied based on traffic percentage.

        Uses consistent hashing so the same session always gets
        the same treatment (fix or no fix).

        Args:
            session_hash: Hash of session ID for consistent bucketing.

        Returns:
            True if fix should be applied.
        """
        if self.traffic_percentage >= 100:
            return True
        if self.traffic_percentage <= 0:
            return False

        # Use modulo for consistent bucketing
        bucket = session_hash % 100
        return bucket < self.traffic_percentage

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary."""
        return {
            "fix_id": self.fix_id,
            "deployment_id": self.deployment_id,
            "error_code": self.error_code,
            "fix_type": self.fix_type,
            "config": self.config,
            "traffic_percentage": self.traffic_percentage,
            "version": self.version,
        }

    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> "ActiveFix":
        """Create from dictionary."""
        return cls(
            fix_id=data["fix_id"],
            deployment_id=data["deployment_id"],
            error_code=data["error_code"],
            fix_type=data["fix_type"],
            config=data.get("config", {}),
            traffic_percentage=data.get("traffic_percentage", 100),
            version=data.get("version", 1),
        )
