"""Savings tracker — calculates real-time cost savings vs cloud APIs.

Turns the invisible benefit of self-hosting into a visible dollar amount.
Every request gets a "cloud equivalent cost" based on current per-token
prices for the equivalent cloud model. Cumulative savings are tracked
per session, day, and month.

Nobody else does this. Not Ollama, not LocalAI, not anyone.
"""

from __future__ import annotations

import logging
import re
import time
from dataclasses import dataclass, field

logger = logging.getLogger(__name__)

# Cloud API pricing per 1M tokens (input/output) as of Feb 2026.
# Conservative estimates — actual prices may be higher.
_CLOUD_PRICING: dict[str, tuple[float, float]] = {
    # (input_per_1m, output_per_1m)
    # Tier 1: Small local models → compare against cheapest cloud
    "tiny": (0.10, 0.30),  # ~GPT-4o-mini / Claude Haiku pricing
    # Tier 2: Medium local models → compare against mid-tier cloud
    "small": (0.25, 0.75),  # ~GPT-4o-mini / Claude Sonnet pricing
    "medium": (1.00, 3.00),  # ~GPT-4o / Claude Sonnet pricing
    # Tier 3: Large local models → compare against premium cloud
    "large": (2.50, 10.00),  # ~GPT-4 / Claude Opus pricing
    "xl": (5.00, 15.00),  # ~GPT-4-turbo / Claude Opus pricing
}

# Map model name patterns to cloud pricing tiers.
# Order matters: checked largest → smallest.
# Numeric patterns use regex with negative lookbehind to prevent "2b" matching inside "22b".
_MODEL_TIER_MAP: list[tuple[list[str], str]] = [
    (["70b", "72b", "65b"], "xl"),
    (["32b", "34b", "22b", "27b", "20b", "gpt-oss"], "xl"),
    (["13b", "14b", "12b", "8x7b"], "large"),
    (["7b", "8b", "6.7b"], "medium"),
    (["3b", "4b"], "small"),
    (["1.7b", "1.5b", "2b", "1b", "mini", "tiny", "nano"], "tiny"),
]

# Electricity cost estimate: $0.12/kWh average US, ~300W GPU, ~$0.036/hr
_ELECTRICITY_COST_PER_HOUR = 0.036
_TOKENS_PER_SECOND_ESTIMATE = 30  # Conservative average across models


def _model_to_tier(model_name: str) -> str:
    """Map a local model name to a cloud pricing tier.

    Uses regex negative lookbehind so "2b" doesn't match inside "22b" or "12b".
    Non-numeric patterns ("mini", "tiny", "nano") use plain substring matching.
    """
    name_lower = model_name.lower()
    for patterns, tier in _MODEL_TIER_MAP:
        for pattern in patterns:
            if pattern[0].isdigit():
                # Numeric pattern — prevent "2b" matching inside "22b"
                if re.search(r"(?<!\d)" + re.escape(pattern), name_lower):
                    return tier
            elif pattern in name_lower:
                return tier
    return "medium"  # Default to medium tier if unknown


def _cloud_cost(tier: str, input_tokens: int, output_tokens: int) -> float:
    """Calculate what this request would have cost on cloud APIs."""
    input_price, output_price = _CLOUD_PRICING.get(tier, _CLOUD_PRICING["medium"])
    input_tokens = max(input_tokens, 0)
    output_tokens = max(output_tokens, 0)
    return (input_tokens * input_price + output_tokens * output_price) / 1_000_000


def _local_cost(total_tokens: int) -> float:
    """Estimate local electricity cost for processing tokens."""
    if total_tokens <= 0:
        return 0.0
    seconds = total_tokens / _TOKENS_PER_SECOND_ESTIMATE
    hours = seconds / 3600
    return hours * _ELECTRICITY_COST_PER_HOUR


@dataclass
class SavingsTracker:
    """Tracks cumulative cost savings for the current session.

    Thread-safe via simple atomic operations on numeric fields.

    Usage::

        tracker = SavingsTracker()
        tracker.record_request("llama3.2:8b", input_tokens=500, output_tokens=200)
        print(tracker.summary())
    """

    total_requests: int = 0
    total_input_tokens: int = 0
    total_output_tokens: int = 0
    total_cloud_cost: float = 0.0
    total_local_cost: float = 0.0
    started_at: float = field(default_factory=time.time)

    def record_request(
        self,
        model: str,
        input_tokens: int = 0,
        output_tokens: int = 0,
    ) -> dict[str, float]:
        """Record a completed request and return per-request savings info.

        Returns dict with keys: cloud_cost, local_cost, savings, savings_percent
        """
        tier = _model_to_tier(model)
        cloud = _cloud_cost(tier, input_tokens, output_tokens)
        local = _local_cost(input_tokens + output_tokens)

        self.total_requests += 1
        self.total_input_tokens += input_tokens
        self.total_output_tokens += output_tokens
        self.total_cloud_cost += cloud
        self.total_local_cost += local

        savings = max(cloud - local, 0.0)
        pct = (savings / cloud * 100) if cloud > 0 else 0.0

        return {
            "cloud_cost": round(cloud, 6),
            "local_cost": round(local, 6),
            "savings": round(savings, 6),
            "savings_percent": round(pct, 1),
        }

    @property
    def total_savings(self) -> float:
        return max(self.total_cloud_cost - self.total_local_cost, 0.0)

    @property
    def total_tokens(self) -> int:
        return self.total_input_tokens + self.total_output_tokens

    @property
    def savings_percent(self) -> float:
        if self.total_cloud_cost <= 0:
            return 0.0
        return (self.total_savings / self.total_cloud_cost) * 100

    @property
    def session_hours(self) -> float:
        return (time.time() - self.started_at) / 3600

    def summary(self) -> dict[str, str | float | int]:
        """Human-friendly summary for display."""
        return {
            "requests": self.total_requests,
            "tokens_processed": self.total_tokens,
            "cloud_equivalent": f"${self.total_cloud_cost:.2f}",
            "actual_cost": f"${self.total_local_cost:.4f}",
            "savings": f"${self.total_savings:.2f}",
            "savings_percent": f"{self.savings_percent:.1f}%",
            "session_hours": round(self.session_hours, 1),
        }

    def format_display(self) -> str:
        """Format savings for Rich console display."""
        return (
            f"Tokens: {self.total_tokens:,} | "
            f"Cloud: ${self.total_cloud_cost:.2f} | "
            f"Actual: ${self.total_local_cost:.4f} | "
            f"Saved: ${self.total_savings:.2f} ({self.savings_percent:.0f}%)"
        )
