"""Tests for Python bindings - cost calculation functionality"""

import pytest
import briefcase_ai


class TestCostCalculator:
    def test_cost_calculator_creation(self):
        """Test CostCalculator creation"""
        calculator = briefcase_ai.CostCalculator()
        assert calculator is not None

    def test_estimate_cost_basic(self):
        """Test basic cost estimation"""
        calculator = briefcase_ai.CostCalculator()

        estimate = calculator.estimate_cost("gpt-4", 1000, 500)

        assert estimate.model_name == "gpt-4"
        assert estimate.input_tokens == 1000
        assert estimate.output_tokens == 500
        assert estimate.total_cost > 0
        assert estimate.currency == "USD"

    def test_estimate_cost_unknown_model(self):
        """Test cost estimation with unknown model"""
        calculator = briefcase_ai.CostCalculator()

        with pytest.raises(Exception):
            calculator.estimate_cost("unknown-model", 1000, 500)

    def test_estimate_cost_invalid_tokens(self):
        """Test cost estimation with invalid token counts"""
        calculator = briefcase_ai.CostCalculator()

        # Zero tokens
        with pytest.raises(Exception):
            calculator.estimate_cost("gpt-4", 0, 0)

        # Exceeding context window
        with pytest.raises(Exception):
            calculator.estimate_cost("gpt-4", 10000, 0)

    def test_estimate_cost_from_text(self):
        """Test cost estimation from text"""
        calculator = briefcase_ai.CostCalculator()

        text = "This is a sample text for cost estimation."
        estimate = calculator.estimate_cost_from_text("gpt-3.5-turbo", text, 100)

        assert estimate.input_tokens > 0
        assert estimate.output_tokens == 100
        assert estimate.total_cost > 0

    def test_check_budget(self):
        """Test budget checking functionality"""
        calculator = briefcase_ai.CostCalculator()

        # OK status
        status = calculator.check_budget(50.0, 100.0)
        assert status.status == "ok"
        assert status.percent_used == 50.0
        assert status.remaining_usd == 50.0

        # Warning status
        status = calculator.check_budget(85.0, 100.0)
        assert status.status == "warning"

        # Critical status
        status = calculator.check_budget(96.0, 100.0)
        assert status.status == "critical"

        # Exceeded status
        status = calculator.check_budget(110.0, 100.0)
        assert status.status == "exceeded"
        assert status.remaining_usd == -10.0

    def test_get_cheapest_model(self):
        """Test finding cheapest model"""
        calculator = briefcase_ai.CostCalculator()

        cheapest = calculator.get_cheapest_model(8000)
        assert cheapest is not None
        assert cheapest.context_window >= 8000

    def test_get_models_under_cost(self):
        """Test finding models under cost threshold"""
        calculator = briefcase_ai.CostCalculator()

        cheap_models = calculator.get_models_under_cost(0.01)
        assert len(cheap_models) > 0

        for model in cheap_models:
            avg_cost = (model.input_cost_per_1k_tokens + model.output_cost_per_1k_tokens) / 2
            assert avg_cost <= 0.01

    def test_get_models_by_provider(self):
        """Test filtering models by provider"""
        calculator = briefcase_ai.CostCalculator()

        openai_models = calculator.get_models_by_provider("openai")
        assert len(openai_models) > 0
        for model in openai_models:
            assert model.provider == "openai"

        anthropic_models = calculator.get_models_by_provider("anthropic")
        assert len(anthropic_models) > 0
        for model in anthropic_models:
            assert model.provider == "anthropic"

    def test_compare_models(self):
        """Test model cost comparison"""
        calculator = briefcase_ai.CostCalculator()

        comparison = calculator.compare_models("gpt-4", "gpt-3.5-turbo", 1000, 500)

        assert comparison.cheaper_model == "gpt-3.5-turbo"
        assert comparison.savings > 0
        assert comparison.percent_difference > 0
        assert comparison.model_a.model_name == "gpt-4"
        assert comparison.model_b.model_name == "gpt-3.5-turbo"

    def test_add_custom_model(self):
        """Test adding custom model pricing"""
        calculator = briefcase_ai.CostCalculator()

        custom_model = briefcase_ai.ModelPricing(
            "custom-model",
            "custom-provider",
            0.001,  # input cost
            0.002,  # output cost
            4096,   # context window
            2048    # max output tokens
        )

        calculator.add_model(custom_model)

        # Test the custom model works
        estimate = calculator.estimate_cost("custom-model", 1000, 500)
        assert estimate.model_name == "custom-model"
        assert estimate.input_cost == 0.001
        assert estimate.output_cost == 0.001  # 500 tokens = 0.5k * 0.002

    def test_remove_model(self):
        """Test removing model from pricing table"""
        calculator = briefcase_ai.CostCalculator()

        # Add custom model first
        custom_model = briefcase_ai.ModelPricing(
            "temp-model", "temp", 0.001, 0.002, 4096, 2048
        )
        calculator.add_model(custom_model)

        # Verify it exists
        estimate = calculator.estimate_cost("temp-model", 1000, 500)
        assert estimate.model_name == "temp-model"

        # Remove it
        removed = calculator.remove_model("temp-model")
        assert removed is not None
        assert removed.model_name == "temp-model"

        # Verify it's gone
        with pytest.raises(Exception):
            calculator.estimate_cost("temp-model", 1000, 500)

    def test_get_all_models(self):
        """Test getting all available models"""
        calculator = briefcase_ai.CostCalculator()

        models = calculator.get_all_models()
        assert len(models) > 0

        # Should include default models
        model_names = [m.model_name for m in models]
        assert "gpt-4" in model_names
        assert "claude-3-sonnet" in model_names
        assert "gpt-3.5-turbo" in model_names

    def test_project_monthly_cost(self):
        """Test monthly cost projection"""
        calculator = briefcase_ai.CostCalculator()

        projection = calculator.project_monthly_cost("gpt-4", 4000, 2000, 30.0)

        assert projection.model_name == "gpt-4"
        assert projection.daily_cost > 0
        assert projection.monthly_cost == projection.daily_cost * 30.0
        assert projection.annual_cost == projection.monthly_cost * 12.0
        assert projection.currency == "USD"


class TestModelPricing:
    def test_model_pricing_creation(self):
        """Test ModelPricing creation"""
        pricing = briefcase_ai.ModelPricing(
            "test-model",
            "test-provider",
            0.01,   # input cost
            0.02,   # output cost
            8192,   # context window
            4096    # max output tokens
        )

        assert pricing.model_name == "test-model"
        assert pricing.provider == "test-provider"
        assert pricing.input_cost_per_1k_tokens == 0.01
        assert pricing.output_cost_per_1k_tokens == 0.02
        assert pricing.context_window == 8192
        assert pricing.max_output_tokens == 4096

    def test_model_pricing_to_object(self):
        """Test ModelPricing serialization"""
        pricing = briefcase_ai.ModelPricing(
            "test-model", "test-provider", 0.01, 0.02, 8192, 4096
        )

        obj = pricing.to_object()
        assert "model_name" in obj
        assert "provider" in obj
        assert "input_cost_per_1k_tokens" in obj


class TestCostIntegration:
    def test_realistic_cost_analysis(self):
        """Test realistic AI cost analysis scenario"""
        calculator = briefcase_ai.CostCalculator()

        # Analyze different models for a chatbot application
        models_to_test = ["gpt-4", "gpt-3.5-turbo", "claude-3-sonnet"]
        daily_input_tokens = 5000
        daily_output_tokens = 2000

        results = {}
        for model in models_to_test:
            try:
                projection = calculator.project_monthly_cost(
                    model, daily_input_tokens, daily_output_tokens, 30.0
                )
                results[model] = projection.monthly_cost
            except Exception:
                continue  # Skip if model not available

        assert len(results) > 0

        # Find the most cost-effective option
        cheapest_model = min(results, key=results.get)
        assert cheapest_model is not None

    def test_budget_monitoring_workflow(self):
        """Test complete budget monitoring workflow"""
        calculator = briefcase_ai.CostCalculator()
        budget = 1000.0  # $1000 monthly budget
        current_spend = 750.0  # $750 spent so far

        # Check budget status
        status = calculator.check_budget(current_spend, budget)
        assert status.status == "ok"  # Under 80%

        # Estimate cost for additional usage
        additional_estimate = calculator.estimate_cost("gpt-4", 10000, 5000)

        # Check if additional usage would exceed budget
        projected_spend = current_spend + additional_estimate.total_cost
        new_status = calculator.check_budget(projected_spend, budget)

        # Should provide warning or alert based on total
        assert new_status.status in ["ok", "warning", "critical", "exceeded"]

    def test_model_selection_optimization(self):
        """Test optimizing model selection based on requirements"""
        calculator = briefcase_ai.CostCalculator()

        # Requirements: need 16k context window, budget conscious
        min_context = 16000
        max_cost_per_1k = 0.01

        # Find suitable models
        large_context_models = calculator.get_cheapest_model(min_context)
        budget_models = calculator.get_models_under_cost(max_cost_per_1k)

        # Should find at least some options
        assert large_context_models is not None

        # Test specific model comparisons
        if budget_models:
            # Compare budget models
            budget_model_names = [m.model_name for m in budget_models]
            if len(budget_model_names) >= 2:
                comparison = calculator.compare_models(
                    budget_model_names[0],
                    budget_model_names[1],
                    5000, 2000
                )
                assert comparison.cheaper_model in budget_model_names


if __name__ == "__main__":
    pytest.main([__file__])