"""Unit tests for language detection module."""

from __future__ import annotations

from extractor.lang_detect import detect, is_available, token_budget_scale

# ---------------------------------------------------------------------------
# detect()
# ---------------------------------------------------------------------------


def test_detect_returns_none_for_short_text():
    """Texts shorter than min_chars threshold return None."""
    result = detect("Hi", min_chars=50)
    assert result is None


def test_detect_respects_min_chars_boundary():
    """Text exactly at min_chars should be attempted; just below returns None."""
    short = "a" * 49
    result = detect(short, min_chars=50)
    assert result is None


def test_detect_returns_none_without_langdetect():
    """detect() returns None when langdetect is not available."""
    import extractor.lang_detect as ld

    original = ld._AVAILABLE
    ld._AVAILABLE = False
    try:
        result = detect("This is a long enough English text to detect language from properly.")
        assert result is None
    finally:
        ld._AVAILABLE = original


def test_detect_returns_string_or_none_for_long_text():
    """For a sufficiently long text, detect returns a string tag or None."""
    text = "The quick brown fox jumps over the lazy dog. " * 5
    result = detect(text, min_chars=20)
    # Either a language string or None (if library not installed)
    assert result is None or isinstance(result, str)


def test_detect_exception_returns_none():
    """detect() swallows exceptions and returns None."""
    import unittest.mock as mock

    import extractor.lang_detect as ld

    original = ld._AVAILABLE
    ld._AVAILABLE = True
    # Patch the detect call inside the module regardless of which name it lives under
    with mock.patch.object(ld, "_ld_detect", side_effect=Exception("boom"), create=True):
        try:
            result = detect("This is a long enough string to trigger detection call here.")
            assert result is None
        finally:
            ld._AVAILABLE = original


# ---------------------------------------------------------------------------
# is_available()
# ---------------------------------------------------------------------------


def test_is_available_returns_bool():
    result = is_available()
    assert isinstance(result, bool)


# ---------------------------------------------------------------------------
# token_budget_scale()
# ---------------------------------------------------------------------------


def test_token_budget_scale_chinese_simplified():
    assert token_budget_scale("zh-cn") == 0.5


def test_token_budget_scale_chinese_traditional():
    assert token_budget_scale("zh-tw") == 0.5


def test_token_budget_scale_chinese_generic():
    assert token_budget_scale("zh") == 0.5


def test_token_budget_scale_japanese():
    assert token_budget_scale("ja") == 0.5


def test_token_budget_scale_korean():
    assert token_budget_scale("ko") == 0.5


def test_token_budget_scale_arabic():
    assert token_budget_scale("ar") == 0.7


def test_token_budget_scale_farsi():
    assert token_budget_scale("fa") == 0.7


def test_token_budget_scale_thai():
    assert token_budget_scale("th") == 0.7


def test_token_budget_scale_hebrew():
    assert token_budget_scale("he") == 0.8


def test_token_budget_scale_english():
    assert token_budget_scale("en") == 1.0


def test_token_budget_scale_none():
    assert token_budget_scale(None) == 1.0


def test_token_budget_scale_unknown_lang():
    assert token_budget_scale("xyz") == 1.0


def test_token_budget_scale_spanish():
    assert token_budget_scale("es") == 1.0


def test_token_budget_scale_french():
    assert token_budget_scale("fr") == 1.0


def test_token_budget_scale_returns_float():
    result = token_budget_scale("en")
    assert isinstance(result, float)
