"""Tests for proxy handler utilities."""

import pytest

from backend.proxy.handler import (
    _calculate_cost,
    _detect_images,
    _estimate_tokens,
    _extract_prompt,
    _parse_strategy,
)
from backend.config import ModelConfig


@pytest.fixture
def model():
    return ModelConfig(
        id="test-model",
        input_cost_per_mtok=2.5,
        output_cost_per_mtok=10.0,
        cache_read_cost_per_mtok=0.25,
        cache_creation_cost_per_mtok=3.75,
    )


class TestCalculateCost:
    def test_basic_cost(self, model):
        cost = _calculate_cost(model, tokens_in=1000, tokens_out=500)
        # 1000 * 2.5 / 1M + 500 * 10.0 / 1M = 0.0025 + 0.005 = 0.0075
        assert abs(cost - 0.0075) < 0.0001

    def test_cost_with_cache_read(self, model):
        cost = _calculate_cost(
            model,
            tokens_in=1000,
            tokens_out=500,
            cache_read_tokens=200,
        )
        # Regular input: 800 * 2.5 / 1M = 0.002
        # Cache read: 200 * 0.25 / 1M = 0.00005
        # Output: 500 * 10.0 / 1M = 0.005
        expected = 0.002 + 0.00005 + 0.005
        assert abs(cost - expected) < 0.0001

    def test_cost_with_cache_creation(self, model):
        cost = _calculate_cost(
            model,
            tokens_in=1000,
            tokens_out=500,
            cache_creation_tokens=300,
        )
        # Regular input: 700 * 2.5 / 1M = 0.00175
        # Cache creation: 300 * 3.75 / 1M = 0.001125
        # Output: 500 * 10.0 / 1M = 0.005
        expected = 0.00175 + 0.001125 + 0.005
        assert abs(cost - expected) < 0.0001

    def test_cost_with_all_cache_types(self, model):
        cost = _calculate_cost(
            model,
            tokens_in=1000,
            tokens_out=500,
            cache_read_tokens=200,
            cache_creation_tokens=300,
        )
        # Regular input: 500 * 2.5 / 1M = 0.00125
        # Cache read: 200 * 0.25 / 1M = 0.00005
        # Cache creation: 300 * 3.75 / 1M = 0.001125
        # Output: 500 * 10.0 / 1M = 0.005
        expected = 0.00125 + 0.00005 + 0.001125 + 0.005
        assert abs(cost - expected) < 0.0001

    def test_zero_tokens(self, model):
        cost = _calculate_cost(model, tokens_in=0, tokens_out=0)
        assert cost == 0.0


class TestDetectImages:
    def test_no_images(self):
        messages = [
            {"role": "user", "content": "Hello"},
            {"role": "assistant", "content": "Hi"},
        ]
        assert _detect_images(messages) is False

    def test_image_url_detected(self):
        messages = [
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": "What's in this image?"},
                    {"type": "image_url", "image_url": {"url": "https://example.com/img.png"}},
                ],
            },
        ]
        assert _detect_images(messages) is True

    def test_image_type_detected(self):
        messages = [
            {
                "role": "user",
                "content": [
                    {"type": "image", "source": {"type": "base64", "data": "abc"}},
                ],
            },
        ]
        assert _detect_images(messages) is True

    def test_text_only_array(self):
        messages = [
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": "Hello"},
                    {"type": "text", "text": "World"},
                ],
            },
        ]
        assert _detect_images(messages) is False


class TestEstimateTokens:
    def test_string_content(self):
        messages = [{"role": "user", "content": "Hello world"}]
        tokens = _estimate_tokens(messages)
        # "Hello world" = 11 chars / 4 ≈ 2
        assert tokens >= 1

    def test_array_content(self):
        messages = [
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": "Hello world"},
                ],
            },
        ]
        tokens = _estimate_tokens(messages)
        assert tokens >= 1

    def test_empty_messages(self):
        tokens = _estimate_tokens([])
        assert tokens == 1  # max(1, 0)

    def test_multiple_messages(self):
        messages = [
            {"role": "user", "content": "Hello"},
            {"role": "assistant", "content": "Hi there"},
            {"role": "user", "content": "How are you?"},
        ]
        tokens = _estimate_tokens(messages)
        assert tokens > 0


class TestExtractPrompt:
    def test_extract_last_user_message(self):
        messages = [
            {"role": "user", "content": "First"},
            {"role": "assistant", "content": "Response"},
            {"role": "user", "content": "Second"},
        ]
        prompt = _extract_prompt(messages)
        assert prompt == "Second"

    def test_extract_from_array_content(self):
        messages = [
            {
                "role": "user",
                "content": [
                    {"type": "text", "text": "Part 1"},
                    {"type": "text", "text": "Part 2"},
                ],
            },
        ]
        prompt = _extract_prompt(messages)
        assert prompt == "Part 1 Part 2"

    def test_no_user_message(self):
        messages = [
            {"role": "system", "content": "You are helpful"},
            {"role": "assistant", "content": "Hello"},
        ]
        prompt = _extract_prompt(messages)
        assert prompt == ""

    def test_empty_messages(self):
        prompt = _extract_prompt([])
        assert prompt == ""


class TestParseStrategy:
    def test_auto(self):
        strategy, direct = _parse_strategy("auto")
        assert strategy == "auto"
        assert direct is None

    def test_auto_best(self):
        strategy, direct = _parse_strategy("auto:best")
        assert strategy == "best"
        assert direct is None

    def test_auto_cheap(self):
        strategy, direct = _parse_strategy("auto:cheap")
        assert strategy == "cheap"
        assert direct is None

    def test_direct_model_simple(self):
        strategy, direct = _parse_strategy("gpt-4o")
        assert strategy == "auto"
        assert direct == "gpt-4o"

    def test_direct_model_with_provider(self):
        strategy, direct = _parse_strategy("openai/gpt-4o")
        assert strategy == "auto"
        assert direct == "openai/gpt-4o"

    def test_direct_model_anthropic(self):
        strategy, direct = _parse_strategy("anthropic/claude-sonnet-4-20250514")
        assert strategy == "auto"
        assert direct == "anthropic/claude-sonnet-4-20250514"
