import json
import pytest
from pathlib import Path
from unittest.mock import MagicMock, patch
from transduck.config import TransduckConfig
from transduck.backend import translate, translate_plural, detect_language
from transduck.providers.prompts import build_messages, build_plural_messages


def _make_config(**overrides):
    defaults = dict(
        project_name="test", project_context="A travel site about Mallorca",
        source_lang="EN", target_langs=["DE"],
        storage_path=Path("/tmp/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,
    )
    defaults.update(overrides)
    return TransduckConfig(**defaults)


def test_build_messages():
    messages = build_messages(
        source_text="Our Events",
        source_lang="EN",
        target_lang="DE",
        project_context="A travel site about Mallorca",
        string_context="Events are concerts and shows",
    )
    assert len(messages) == 2
    assert messages[0]["role"] == "system"
    assert "EN" in messages[0]["content"]
    assert "DE" in messages[0]["content"]
    assert "Mallorca" in messages[0]["content"]
    assert messages[1]["role"] == "user"
    assert "Our Events" in messages[1]["content"]
    assert "concerts and shows" in messages[1]["content"]


def test_build_messages_no_string_context():
    messages = build_messages(
        source_text="Book Now",
        source_lang="EN",
        target_lang="DE",
        project_context="A travel site",
        string_context=None,
    )
    assert "none" in messages[1]["content"].lower()


@patch("transduck.providers.openai_provider.openai")
def test_translate_returns_text(mock_openai_module):
    mock_client = MagicMock()
    mock_openai_module.OpenAI.return_value = mock_client
    mock_client.chat.completions.create.return_value = MagicMock(
        choices=[MagicMock(message=MagicMock(content="Unsere Veranstaltungen"))]
    )
    cfg = _make_config()
    with patch.dict("os.environ", {"OPENAI_API_KEY": "test-key"}):
        result = translate(
            source_text="Our Events", source_lang="EN", target_lang="DE",
            project_context="A travel site", string_context=None, config=cfg,
        )
    assert result == "Unsere Veranstaltungen"


@patch("transduck.providers.openai_provider.openai")
def test_translate_strips_whitespace(mock_openai_module):
    mock_client = MagicMock()
    mock_openai_module.OpenAI.return_value = mock_client
    mock_client.chat.completions.create.return_value = MagicMock(
        choices=[MagicMock(message=MagicMock(content="  Hallo  \n"))]
    )
    cfg = _make_config()
    with patch.dict("os.environ", {"OPENAI_API_KEY": "test-key"}):
        result = translate(
            source_text="Hello", source_lang="EN", target_lang="DE",
            project_context="test", string_context=None, config=cfg,
        )
    assert result == "Hallo"


@patch("transduck.providers.openai_provider.openai")
def test_translate_raises_on_api_error(mock_openai_module):
    mock_client = MagicMock()
    mock_openai_module.OpenAI.return_value = mock_client
    mock_client.chat.completions.create.side_effect = Exception("API error")
    cfg = _make_config()
    with patch.dict("os.environ", {"OPENAI_API_KEY": "test-key"}):
        with pytest.raises(Exception, match="API error"):
            translate(
                source_text="Hello", source_lang="EN", target_lang="DE",
                project_context="test", string_context=None, config=cfg,
            )


def test_build_plural_messages():
    messages = build_plural_messages(
        one="{count} event",
        other="{count} events",
        source_lang="EN",
        target_lang="DE",
        project_context="A travel site",
        string_context="Events are concerts",
    )
    assert len(messages) == 2
    assert messages[0]["role"] == "system"
    assert "CLDR" in messages[0]["content"]
    assert "JSON" in messages[0]["content"]
    assert messages[1]["role"] == "user"
    assert "{count} event" in messages[1]["content"]
    assert "{count} events" in messages[1]["content"]


def test_build_plural_messages_no_context():
    messages = build_plural_messages(
        one="1 item", other="{count} items",
        source_lang="EN", target_lang="RU",
        project_context="test", string_context=None,
    )
    assert "none" in messages[1]["content"].lower()


@patch("transduck.providers.openai_provider.openai")
def test_translate_plural_returns_dict(mock_openai_module):
    mock_client = MagicMock()
    mock_openai_module.OpenAI.return_value = mock_client
    response_json = json.dumps({"one": "{count} Nachricht", "other": "{count} Nachrichten"})
    mock_client.chat.completions.create.return_value = MagicMock(
        choices=[MagicMock(message=MagicMock(content=response_json))]
    )
    cfg = _make_config()
    with patch.dict("os.environ", {"OPENAI_API_KEY": "test-key"}):
        result = translate_plural(
            one="{count} message", other="{count} messages",
            source_lang="EN", target_lang="DE",
            project_context="test", string_context=None, config=cfg,
        )
    assert result == {"one": "{count} Nachricht", "other": "{count} Nachrichten"}


@patch("transduck.providers.openai_provider.openai")
def test_detect_language_returns_code(mock_openai_module):
    mock_client = MagicMock()
    mock_openai_module.OpenAI.return_value = mock_client
    mock_client.chat.completions.create.return_value = MagicMock(
        choices=[MagicMock(message=MagicMock(content="ES"))]
    )
    cfg = _make_config()
    with patch.dict("os.environ", {"OPENAI_API_KEY": "test-key"}):
        result = detect_language("Hola, ¿cómo estás?", cfg)
    assert result == "ES"


@patch("transduck.providers.openai_provider.openai")
def test_detect_language_normalizes_to_uppercase(mock_openai_module):
    mock_client = MagicMock()
    mock_openai_module.OpenAI.return_value = mock_client
    mock_client.chat.completions.create.return_value = MagicMock(
        choices=[MagicMock(message=MagicMock(content="  fr  \n"))]
    )
    cfg = _make_config()
    with patch.dict("os.environ", {"OPENAI_API_KEY": "test-key"}):
        result = detect_language("Bonjour le monde", cfg)
    assert result == "FR"
