import hashlib
import pytest
from unittest.mock import patch
import transduck
from transduck import ait_plural, set_language
from transduck.config import TransduckConfig


def _hash(text: str) -> str:
    return hashlib.sha256(text.encode()).hexdigest()


@pytest.fixture
def mock_config(tmp_path):
    return TransduckConfig(
        project_name="test",
        project_context="A test site",
        source_lang="EN",
        target_langs=["DE", "ES"],
        storage_path=tmp_path / "test.db",
        provider="openai",
        api_key_env="OPENAI_API_KEY",
        token_env="",
        backend_model="gpt-4.1-mini",
        backend_timeout=10,
        backend_max_retries=2,
        shared_url=None,
        read_only=False,
    )


@pytest.fixture(autouse=True)
def reset_state():
    transduck._state = transduck._State()
    yield
    transduck._wait_for_background(timeout=2.0)
    transduck._state = transduck._State()


@pytest.fixture
def initialized(mock_config, monkeypatch):
    monkeypatch.setenv("OPENAI_API_KEY", "test-key")
    transduck.initialize(mock_config)
    set_language("DE")


def test_ait_plural_same_language_singular(initialized):
    set_language("EN")
    result = ait_plural("{count} message", "{count} messages", count=1)
    assert result == "1 message"


def test_ait_plural_same_language_plural(initialized):
    set_language("EN")
    result = ait_plural("{count} message", "{count} messages", count=5)
    assert result == "5 messages"


def test_ait_plural_cache_hit(initialized):
    source_key = "{count} message\x00{count} messages"
    pch = _hash("A test site")
    sch = _hash("")
    transduck._state.store.insert_plural(
        source_text=source_key, source_lang="EN", target_lang="DE",
        project_context_hash=pch, string_context_hash=sch,
        plural_category="one", translated_text="{count} Nachricht", model="gpt-4.1-mini",
        string_context="",
    )
    transduck._state.store.insert_plural(
        source_text=source_key, source_lang="EN", target_lang="DE",
        project_context_hash=pch, string_context_hash=sch,
        plural_category="other", translated_text="{count} Nachrichten", model="gpt-4.1-mini",
        string_context="",
    )
    result = ait_plural("{count} message", "{count} messages", count=1)
    assert result == "1 Nachricht"
    result = ait_plural("{count} message", "{count} messages", count=5)
    assert result == "5 Nachrichten"


@patch("transduck.backend.translate_plural")
def test_ait_plural_cache_miss_calls_backend(mock_tp, initialized):
    mock_tp.return_value = {"one": "{count} Nachricht", "other": "{count} Nachrichten"}
    result = ait_plural("{count} message", "{count} messages", count=5)
    assert result == "5 Nachrichten"
    mock_tp.assert_called_once()


@patch("transduck.backend.translate_plural")
def test_ait_plural_caches_after_miss(mock_tp, initialized):
    mock_tp.return_value = {"one": "{count} Nachricht", "other": "{count} Nachrichten"}
    ait_plural("{count} message", "{count} messages", count=5)
    mock_tp.reset_mock()
    result = ait_plural("{count} message", "{count} messages", count=1)
    assert result == "1 Nachricht"
    mock_tp.assert_not_called()


@patch("transduck.backend.translate_plural")
def test_ait_plural_backend_failure_falls_back(mock_tp, initialized):
    mock_tp.side_effect = Exception("API down")
    result = ait_plural("{count} message", "{count} messages", count=5)
    assert result == "5 messages"


def test_ait_plural_with_vars(initialized):
    source_key = "{count} item for {name}\x00{count} items for {name}"
    pch = _hash("A test site")
    sch = _hash("")
    transduck._state.store.insert_plural(
        source_text=source_key, source_lang="EN", target_lang="DE",
        project_context_hash=pch, string_context_hash=sch,
        plural_category="one", translated_text="{count} Artikel für {name}", model="gpt-4.1-mini",
        string_context="",
    )
    transduck._state.store.insert_plural(
        source_text=source_key, source_lang="EN", target_lang="DE",
        project_context_hash=pch, string_context_hash=sch,
        plural_category="other", translated_text="{count} Artikel für {name}", model="gpt-4.1-mini",
        string_context="",
    )
    result = ait_plural("{count} item for {name}", "{count} items for {name}",
                        count=3, vars={"name": "Tim"})
    assert result == "3 Artikel für Tim"


def test_ait_plural_raises_if_not_initialized():
    with pytest.raises(RuntimeError):
        ait_plural("{count} msg", "{count} msgs", count=1)
