# #region Test.PreviewTokenEstimator [C:2] [TYPE Module] [SEMANTICS test, translate, token, cost, estimation]
# @BRIEF Tests for preview_token_estimator.py — TokenEstimator static methods.
# @RELATION BINDS_TO -> [TokenEstimator]
# @TEST_CONTRACT: TokenEstimator.estimate_prompt_tokens -> int | token estimate from string
# @TEST_CONTRACT: TokenEstimator.estimate_output_tokens -> int | output token estimate
# @TEST_CONTRACT: TokenEstimator.estimate_cost -> float | cost estimate from tokens
# @TEST_CONTRACT: TokenEstimator.check_cost_warning -> str | None | cost threshold warning

import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent / "src"))

import os
os.environ.setdefault("SECRET_KEY", "test-secret-key-for-testing")
os.environ.setdefault("DATABASE_URL", "sqlite:///:memory:")
os.environ.setdefault("AUTH_DATABASE_URL", "sqlite:///:memory:")

import pytest

from src.plugins.translate.preview_token_estimator import TokenEstimator


class TestEstimatePromptTokens:
    """TokenEstimator.estimate_prompt_tokens — estimate tokens from string."""

    def test_empty_string_returns_zero(self):
        """Empty string returns 0."""
        assert TokenEstimator.estimate_prompt_tokens("") == 0

    def test_short_string_returns_at_least_one(self):
        """Short string returns at least 1."""
        assert TokenEstimator.estimate_prompt_tokens("a") == 1

    def test_long_string_estimates(self):
        """Longer string produces token estimate."""
        text = "hello world " * 100  # ~1300 chars
        tokens = TokenEstimator.estimate_prompt_tokens(text)
        assert tokens > 0
        assert tokens <= len(text)  # tokens shouldn't exceed chars

    def test_empty_string_handled(self):
        """Empty string returns 0. Whitespace is truthy so gets min 1."""
        assert TokenEstimator.estimate_prompt_tokens("") == 0
        assert TokenEstimator.estimate_prompt_tokens("   ") == 1


class TestEstimateOutputTokens:
    """TokenEstimator.estimate_output_tokens — estimate output tokens."""

    def test_zero_rows_returns_zero(self):
        """0 rows returns 0."""
        assert TokenEstimator.estimate_output_tokens(0) == 0

    def test_single_row_single_language(self):
        """1 row, 1 language gives output estimate."""
        result = TokenEstimator.estimate_output_tokens(1, 1)
        expected = int(1 * 1 * 120 * 1.2)
        assert result == expected

    def test_multi_row_single_language(self):
        """10 rows, 1 language."""
        result = TokenEstimator.estimate_output_tokens(10, 1)
        expected = int(10 * 1 * 120 * 1.2)
        assert result == expected

    def test_multi_row_multi_language(self):
        """5 rows, 3 languages."""
        result = TokenEstimator.estimate_output_tokens(5, 3)
        expected = int(5 * 3 * 120 * 1.2)
        assert result == expected

    def test_default_language(self):
        """Default num_languages is 1."""
        result = TokenEstimator.estimate_output_tokens(2)
        expected = int(2 * 1 * 120 * 1.2)
        assert result == expected


class TestEstimateCost:
    """TokenEstimator.estimate_cost — cost from tokens."""

    def test_zero_tokens_zero_cost(self):
        """0 tokens costs 0."""
        assert TokenEstimator.estimate_cost(0) == 0.0

    def test_default_rate(self):
        """1000 tokens at default rate."""
        cost = TokenEstimator.estimate_cost(1000)
        assert cost == pytest.approx(0.002, 0.000001)

    def test_custom_rate(self):
        """Custom cost per 1k tokens."""
        cost = TokenEstimator.estimate_cost(1000, 0.01)
        assert cost == pytest.approx(0.01, 0.000001)

    def test_large_token_count(self):
        """Large token count calculates correctly."""
        cost = TokenEstimator.estimate_cost(100000)
        assert cost == pytest.approx(0.2, 0.000001)

    def test_rounding_precision(self):
        """Result is rounded to 6 decimal places."""
        cost = TokenEstimator.estimate_cost(333)
        assert isinstance(cost, float)


class TestCheckCostWarning:
    """TokenEstimator.check_cost_warning — cost threshold warning."""

    def test_below_threshold_no_warning(self):
        """sample_size <= 30 returns None."""
        assert TokenEstimator.check_cost_warning(10, 1, 100, 0.001) is None
        assert TokenEstimator.check_cost_warning(30, 1, 100, 0.001) is None

    def test_above_threshold_returns_warning(self):
        """sample_size > 30 returns warning string."""
        warning = TokenEstimator.check_cost_warning(50, 2, 5000, 0.05)
        assert warning is not None
        assert "Large preview" in warning
        assert "5000 tokens" in warning
        assert "$0.0500" in warning
        assert "2 languages" in warning

    def test_warning_format_high_cost(self):
        """Warning includes formatted cost."""
        warning = TokenEstimator.check_cost_warning(100, 1, 10000, 0.5)
        assert warning is not None
        assert "$0.5000" in warning

    def test_single_language_format(self):
        """Warning for single language."""
        warning = TokenEstimator.check_cost_warning(40, 1, 2000, 0.004)
        assert warning is not None
        assert "1 languages" in warning
# #endregion Test.PreviewTokenEstimator
