"""
Tests for metrics routes cost calculation.

Tests cover:
- Cost calculation per model
- Cost analytics
"""

from datetime import datetime, timedelta


class TestCostCalculation:
    """Tests for cost calculation."""

    def test_cost_calculation_per_model(self):
        """Cost is calculated per model."""
        pricing = {
            "gpt-4": {"prompt": 0.03, "completion": 0.06},
            "gpt-3.5-turbo": {"prompt": 0.0015, "completion": 0.002},
            "claude-3-opus": {"prompt": 0.015, "completion": 0.075},
        }

        model = "gpt-4"
        prompt_tokens = 1000
        completion_tokens = 500

        cost = (
            pricing[model]["prompt"] * prompt_tokens / 1000
            + pricing[model]["completion"] * completion_tokens / 1000
        )

        assert cost == 0.06  # 0.03 + 0.03

    def test_cost_calculation_prompt_tokens(self):
        """Prompt token cost is calculated."""
        prompt_price_per_1k = 0.03
        prompt_tokens = 2500

        prompt_cost = prompt_price_per_1k * prompt_tokens / 1000

        assert prompt_cost == 0.075

    def test_cost_calculation_completion_tokens(self):
        """Completion token cost is calculated."""
        completion_price_per_1k = 0.06
        completion_tokens = 1000

        completion_cost = completion_price_per_1k * completion_tokens / 1000

        assert completion_cost == 0.06

    def test_cost_calculation_total(self):
        """Total cost is sum of prompt and completion."""
        prompt_cost = 0.03
        completion_cost = 0.06

        total_cost = prompt_cost + completion_cost

        assert total_cost == 0.09

    def test_cost_calculation_unknown_model(self):
        """Unknown model uses default pricing."""
        pricing = {
            "gpt-4": {"prompt": 0.03, "completion": 0.06},
            "default": {"prompt": 0.01, "completion": 0.02},
        }

        model = "unknown-model"
        prompt_tokens = 1000

        model_pricing = pricing.get(model, pricing["default"])
        cost = model_pricing["prompt"] * prompt_tokens / 1000

        assert cost == 0.01

    def test_cost_calculation_zero_tokens(self):
        """Zero tokens results in zero cost."""
        prompt_tokens = 0
        completion_tokens = 0
        price_per_1k = 0.03

        cost = price_per_1k * (prompt_tokens + completion_tokens) / 1000

        assert cost == 0.0

    def test_cost_calculation_large_numbers(self):
        """Large token counts are calculated correctly."""
        prompt_tokens = 1_000_000
        completion_tokens = 500_000
        prompt_price = 0.03
        completion_price = 0.06

        cost = (
            prompt_price * prompt_tokens / 1000
            + completion_price * completion_tokens / 1000
        )

        assert cost == 60.0  # 30 + 30

    def test_cost_calculation_pricing_cache(self):
        """Pricing is cached for efficiency."""
        pricing_cache = {}
        model = "gpt-4"

        if model not in pricing_cache:
            pricing_cache[model] = {"prompt": 0.03, "completion": 0.06}

        # Second access uses cache
        cached_pricing = pricing_cache.get(model)

        assert cached_pricing is not None
        assert cached_pricing["prompt"] == 0.03

    def test_cost_calculation_research_summation(self):
        """Costs are summed across research phases."""
        phase_costs = [
            {"phase": "analysis", "cost": 0.05},
            {"phase": "synthesis", "cost": 0.15},
            {"phase": "refinement", "cost": 0.08},
        ]

        total_cost = sum(p["cost"] for p in phase_costs)

        assert total_cost == 0.28

    def test_cost_calculation_multiple_models(self):
        """Costs from multiple models are aggregated."""
        usage = [
            {"model": "gpt-4", "cost": 0.50},
            {"model": "gpt-3.5-turbo", "cost": 0.02},
            {"model": "gpt-4", "cost": 0.30},
        ]

        model_costs = {}
        for u in usage:
            model = u["model"]
            model_costs[model] = model_costs.get(model, 0) + u["cost"]

        assert model_costs["gpt-4"] == 0.80
        assert model_costs["gpt-3.5-turbo"] == 0.02


class TestCostAnalytics:
    """Tests for cost analytics."""

    def test_cost_analytics_grouping_by_research(self):
        """Costs are grouped by research ID."""
        costs = [
            {"research_id": 1, "cost": 0.10},
            {"research_id": 1, "cost": 0.15},
            {"research_id": 2, "cost": 0.05},
        ]

        grouped = {}
        for c in costs:
            rid = c["research_id"]
            grouped[rid] = grouped.get(rid, 0) + c["cost"]

        assert grouped[1] == 0.25
        assert grouped[2] == 0.05

    def test_cost_analytics_top_10_expensive(self):
        """Top 10 most expensive researches are returned."""
        research_costs = {f"research_{i}": i * 0.1 for i in range(20)}

        top_10 = dict(
            sorted(research_costs.items(), key=lambda x: x[1], reverse=True)[
                :10
            ]
        )

        assert len(top_10) == 10
        assert "research_19" in top_10
        assert "research_0" not in top_10

    def test_cost_analytics_large_dataset_pagination(self):
        """Large datasets are paginated."""
        all_costs = [{"id": i, "cost": i * 0.01} for i in range(1000)]
        page_size = 50
        page = 2

        start = page * page_size
        end = start + page_size
        paginated = all_costs[start:end]

        assert len(paginated) == 50
        assert paginated[0]["id"] == 100

    def test_cost_analytics_period_filtering(self):
        """Costs are filtered by time period."""
        now = datetime.now()
        costs = [
            {"date": now - timedelta(days=5), "cost": 0.50},
            {"date": now - timedelta(days=15), "cost": 0.30},
            {"date": now - timedelta(days=45), "cost": 0.20},
        ]

        cutoff = now - timedelta(days=30)
        filtered = [c for c in costs if c["date"] > cutoff]

        assert len(filtered) == 2
        assert sum(c["cost"] for c in filtered) == 0.80

    def test_cost_analytics_empty_data(self):
        """Empty data returns zero totals."""
        costs = []

        if not costs:
            result = {"total": 0.0, "average": 0.0, "count": 0}
        else:
            result = {"total": sum(costs)}

        assert result["total"] == 0.0
        assert result["count"] == 0


class TestCostFormatting:
    """Tests for cost formatting."""

    def test_format_cost_two_decimals(self):
        """Costs are formatted to two decimal places."""
        cost = 0.123456

        formatted = f"${cost:.2f}"

        assert formatted == "$0.12"

    def test_format_cost_currency_symbol(self):
        """Costs include currency symbol."""
        cost = 1.50

        formatted = f"${cost:.2f}"

        assert formatted.startswith("$")

    def test_format_cost_large_number(self):
        """Large costs are formatted with commas."""
        cost = 12345.67

        formatted = f"${cost:,.2f}"

        assert formatted == "$12,345.67"

    def test_format_cost_percentage_of_total(self):
        """Cost as percentage of total is calculated."""
        cost = 0.25
        total = 1.00

        percentage = (cost / total) * 100

        assert percentage == 25.0

    def test_format_cost_zero_handling(self):
        """Zero costs are formatted correctly."""
        cost = 0.0

        formatted = f"${cost:.2f}"

        assert formatted == "$0.00"


class TestCostProjections:
    """Tests for cost projections."""

    def test_project_daily_average(self):
        """Daily average cost is projected."""
        costs = [0.10, 0.15, 0.12, 0.18, 0.20, 0.08, 0.17]

        daily_avg = sum(costs) / len(costs)

        assert round(daily_avg, 2) == 0.14

    def test_project_monthly_estimate(self):
        """Monthly cost is estimated from daily average."""
        daily_avg = 0.50

        monthly_estimate = daily_avg * 30

        assert monthly_estimate == 15.0

    def test_project_trend_increasing(self):
        """Increasing cost trend is detected."""
        weekly_costs = [1.0, 1.2, 1.5, 1.8]

        trend = (
            "increasing" if weekly_costs[-1] > weekly_costs[0] else "decreasing"
        )

        assert trend == "increasing"

    def test_project_budget_remaining(self):
        """Budget remaining is calculated."""
        budget = 100.0
        spent = 65.0

        remaining = budget - spent
        percentage_remaining = (remaining / budget) * 100

        assert remaining == 35.0
        assert percentage_remaining == 35.0

    def test_project_days_until_budget_exceeded(self):
        """Days until budget exceeded is calculated."""
        budget = 100.0
        spent = 80.0
        daily_avg = 5.0

        remaining = budget - spent
        days_remaining = remaining / daily_avg

        assert days_remaining == 4.0
