"""Tests for translation functionality."""

import os
import sys

import pytest

# Add src to path for imports
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))

from translate_docx.models import (
    Document,
    DocumentMetadata,
    LineNumbering,
    PageSettings,
    Paragraph,
    ParagraphFormatting,
    RunFormatting,
    Section,
    TextRun,
)
from translate_docx.translator import (
    CallbackTranslator,
    ManualTranslator,
    NoOpTranslator,
    TranslatorInterface,
    translate_document,
)


class TestTranslatorInterface:
    """Test the TranslatorInterface abstract class."""

    def test_should_translate_run_skips_superscript(self):
        """Superscripts should not be translated (citations)."""
        translator = NoOpTranslator()

        # Superscript run
        superscript_run = TextRun(text="1", formatting=RunFormatting(is_superscript=True))
        assert not translator.should_translate_run(superscript_run)

    def test_should_translate_run_skips_subscript(self):
        """Subscripts should not be translated."""
        translator = NoOpTranslator()

        subscript_run = TextRun(text="2", formatting=RunFormatting(is_subscript=True))
        assert not translator.should_translate_run(subscript_run)

    def test_should_translate_run_skips_whitespace(self):
        """Whitespace-only runs should not be translated."""
        translator = NoOpTranslator()

        whitespace_run = TextRun(text="   ", formatting=RunFormatting())
        assert not translator.should_translate_run(whitespace_run)

    def test_should_translate_run_skips_empty(self):
        """Empty runs should not be translated."""
        translator = NoOpTranslator()

        empty_run = TextRun(text="", formatting=RunFormatting())
        assert not translator.should_translate_run(empty_run)

    def test_should_translate_run_allows_normal_text(self):
        """Normal text runs should be translated."""
        translator = NoOpTranslator()

        normal_run = TextRun(text="Hello", formatting=RunFormatting())
        assert translator.should_translate_run(normal_run)

    def test_should_translate_run_allows_formatted_text(self):
        """Formatted text (bold, italic) should be translated."""
        translator = NoOpTranslator()

        bold_italic_run = TextRun(
            text="Important", formatting=RunFormatting(bold=True, italic=True)
        )
        assert translator.should_translate_run(bold_italic_run)


class TestCallbackTranslator:
    """Test CallbackTranslator implementation."""

    def test_callback_translator_calls_function(self):
        """CallbackTranslator should call the provided function."""
        translations = {
            "Hello": "Hallo",
            "World": "Welt",
        }

        def simple_translate(text, source, target):
            return translations.get(text, text)

        translator = CallbackTranslator(simple_translate)
        result = translator.translate("Hello", "en", "de")
        assert result == "Hallo"

    def test_callback_translator_receives_language_codes(self):
        """CallbackTranslator should pass language codes to function."""
        received_langs = {}

        def capture_langs(text, source, target):
            received_langs["source"] = source
            received_langs["target"] = target
            return text

        translator = CallbackTranslator(capture_langs)
        translator.translate("test", "en", "fr")

        assert received_langs["source"] == "en"
        assert received_langs["target"] == "fr"

    def test_callback_translator_with_lambda(self):
        """CallbackTranslator should work with lambda functions."""
        translator = CallbackTranslator(lambda text, src, tgt: text.upper())
        result = translator.translate("hello", "en", "de")
        assert result == "HELLO"


class TestManualTranslator:
    """Test ManualTranslator implementation."""

    def test_manual_translator_returns_translation(self):
        """ManualTranslator should return mapped translation."""
        translations = {
            "Hallo": "Hello",
            "Welt": "World",
        }
        translator = ManualTranslator(translations)

        result = translator.translate("Hallo", "de", "en")
        assert result == "Hello"

    def test_manual_translator_returns_original_if_not_found(self):
        """ManualTranslator should return original text if not in dictionary."""
        translations = {"Hallo": "Hello"}
        translator = ManualTranslator(translations)

        result = translator.translate("Goodbye", "de", "en")
        assert result == "Goodbye"

    def test_manual_translator_handles_empty_dict(self):
        """ManualTranslator should handle empty translation dictionary."""
        translator = ManualTranslator({})

        result = translator.translate("Any text", "en", "fr")
        assert result == "Any text"

    def test_manual_translator_case_sensitive(self):
        """ManualTranslator should be case-sensitive."""
        translations = {"Hello": "Hola"}
        translator = ManualTranslator(translations)

        # Different case, no translation
        result = translator.translate("hello", "en", "es")
        assert result == "hello"


class TestNoOpTranslator:
    """Test NoOpTranslator implementation."""

    def test_noop_translator_returns_unchanged(self):
        """NoOpTranslator should return text unchanged."""
        translator = NoOpTranslator()

        text = "Any text here"
        result = translator.translate(text, "en", "de")
        assert result == text

    def test_noop_translator_ignores_language_codes(self):
        """NoOpTranslator should ignore language codes."""
        translator = NoOpTranslator()

        result = translator.translate("test", "xx", "yy")
        assert result == "test"


class TestTranslateDocument:
    """Test translate_document function."""

    def test_translate_document_simple_paragraph(self):
        """Should translate simple document with single paragraph."""
        doc = Document(
            metadata=DocumentMetadata(
                line_numbering=LineNumbering(),
                page_settings=PageSettings(),
            ),
            sections=[],
            preamble_paragraphs=[
                Paragraph(
                    runs=[TextRun(text="Hallo", formatting=RunFormatting())],
                    formatting=ParagraphFormatting(),
                )
            ],
        )

        translations = {"Hallo": "Hello"}
        translator = ManualTranslator(translations, word_level=True)

        translated = translate_document(doc, translator, "de", "en")

        assert translated.preamble_paragraphs[0].runs[0].text == "Hello"
        # Original should be unchanged
        assert doc.preamble_paragraphs[0].runs[0].text == "Hallo"

    def test_translate_document_multiple_runs(self):
        """Should translate all runs in a paragraph."""
        doc = Document(
            metadata=DocumentMetadata(
                line_numbering=LineNumbering(),
                page_settings=PageSettings(),
            ),
            sections=[],
            preamble_paragraphs=[
                Paragraph(
                    runs=[
                        TextRun(text="Hallo", formatting=RunFormatting()),
                        TextRun(text=" ", formatting=RunFormatting()),
                        TextRun(text="Welt", formatting=RunFormatting()),
                    ],
                    formatting=ParagraphFormatting(),
                )
            ],
        )

        translations = {"Hallo": "Hello", "Welt": "World"}
        translator = ManualTranslator(translations, word_level=True)

        translated = translate_document(doc, translator, "de", "en")

        assert translated.preamble_paragraphs[0].runs[0].text == "Hello"
        assert translated.preamble_paragraphs[0].runs[2].text == "World"

    def test_translate_document_preserves_formatting(self):
        """Should preserve run formatting during translation."""
        doc = Document(
            metadata=DocumentMetadata(
                line_numbering=LineNumbering(),
                page_settings=PageSettings(),
            ),
            sections=[],
            preamble_paragraphs=[
                Paragraph(
                    runs=[
                        TextRun(
                            text="Hallo",
                            formatting=RunFormatting(
                                bold=True,
                                font_name="Arial",
                                font_size=12,
                            ),
                        ),
                    ],
                    formatting=ParagraphFormatting(),
                )
            ],
        )

        translations = {"Hallo": "Hello"}
        translator = ManualTranslator(translations, word_level=True)

        translated = translate_document(doc, translator, "de", "en")

        run = translated.preamble_paragraphs[0].runs[0]
        assert run.text == "Hello"
        assert run.formatting.bold is True
        assert run.formatting.font_name == "Arial"
        assert run.formatting.font_size == 12

    def test_translate_document_skips_superscripts(self):
        """Should skip superscript runs (citations)."""
        doc = Document(
            metadata=DocumentMetadata(
                line_numbering=LineNumbering(),
                page_settings=PageSettings(),
            ),
            sections=[],
            preamble_paragraphs=[
                Paragraph(
                    runs=[
                        TextRun(text="Text", formatting=RunFormatting()),
                        TextRun(
                            text="1",
                            formatting=RunFormatting(is_superscript=True),
                        ),
                    ],
                    formatting=ParagraphFormatting(),
                )
            ],
        )

        translations = {"Text": "Texto", "1": "SHOULD_NOT_TRANSLATE"}
        translator = ManualTranslator(translations, word_level=True)

        translated = translate_document(doc, translator, "es", "en")

        assert translated.preamble_paragraphs[0].runs[0].text == "Texto"
        # Superscript should remain unchanged
        assert translated.preamble_paragraphs[0].runs[1].text == "1"

    def test_translate_document_sections(self):
        """Should translate section headers and body paragraphs."""
        doc = Document(
            metadata=DocumentMetadata(
                line_numbering=LineNumbering(),
                page_settings=PageSettings(),
            ),
            sections=[
                Section(
                    header=Paragraph(
                        runs=[TextRun(text="Abschnitt", formatting=RunFormatting())],
                        formatting=ParagraphFormatting(),
                        is_header=True,
                    ),
                    paragraphs=[
                        Paragraph(
                            runs=[TextRun(text="Inhalt", formatting=RunFormatting())],
                            formatting=ParagraphFormatting(),
                        ),
                    ],
                )
            ],
            preamble_paragraphs=[],
        )

        translations = {"Abschnitt": "Section", "Inhalt": "Content"}
        translator = ManualTranslator(translations, word_level=True)

        translated = translate_document(doc, translator, "de", "en")

        assert translated.sections[0].header.runs[0].text == "Section"
        assert translated.sections[0].paragraphs[0].runs[0].text == "Content"

    def test_translate_document_preserves_structure(self):
        """Should preserve document structure during translation."""
        doc = Document(
            metadata=DocumentMetadata(
                line_numbering=LineNumbering(),
                page_settings=PageSettings(),
            ),
            sections=[
                Section(
                    header=Paragraph(
                        runs=[TextRun(text="Header", formatting=RunFormatting())],
                        formatting=ParagraphFormatting(),
                        is_header=True,
                    ),
                    paragraphs=[
                        Paragraph(
                            runs=[TextRun(text="Para1", formatting=RunFormatting())],
                            formatting=ParagraphFormatting(),
                        ),
                        Paragraph(
                            runs=[TextRun(text="Para2", formatting=RunFormatting())],
                            formatting=ParagraphFormatting(),
                        ),
                    ],
                ),
                Section(
                    header=Paragraph(
                        runs=[TextRun(text="Header2", formatting=RunFormatting())],
                        formatting=ParagraphFormatting(),
                        is_header=True,
                    ),
                    paragraphs=[
                        Paragraph(
                            runs=[TextRun(text="Para3", formatting=RunFormatting())],
                            formatting=ParagraphFormatting(),
                        ),
                    ],
                ),
            ],
            preamble_paragraphs=[],
        )

        translator = NoOpTranslator()
        translated = translate_document(doc, translator, "en", "fr")

        # Check structure is preserved
        assert len(translated.sections) == 2
        assert len(translated.sections[0].paragraphs) == 2
        assert len(translated.sections[1].paragraphs) == 1
        # Check preamble
        assert len(translated.preamble_paragraphs) == 0

    def test_translate_document_preserves_metadata(self):
        """Should preserve document metadata during translation."""
        metadata = DocumentMetadata(
            line_numbering=LineNumbering(
                enabled=True,
                start=1,
                increment=1,
            ),
            page_settings=PageSettings(
                width=9144000,
                height=12700000,
            ),
            default_font="Times New Roman",
            default_font_size=11,
        )

        doc = Document(
            metadata=metadata,
            sections=[],
            preamble_paragraphs=[
                Paragraph(
                    runs=[TextRun(text="Test", formatting=RunFormatting())],
                    formatting=ParagraphFormatting(),
                )
            ],
        )

        translator = NoOpTranslator()
        translated = translate_document(doc, translator, "en", "de")

        assert translated.metadata.line_numbering.enabled is True
        assert translated.metadata.line_numbering.start == 1
        assert translated.metadata.page_settings.width == 9144000
        assert translated.metadata.default_font == "Times New Roman"
        assert translated.metadata.default_font_size == 11

    def test_translate_document_does_not_modify_original(self):
        """Translation should not modify the original document."""
        original_text = "Original"
        doc = Document(
            metadata=DocumentMetadata(
                line_numbering=LineNumbering(),
                page_settings=PageSettings(),
            ),
            sections=[],
            preamble_paragraphs=[
                Paragraph(
                    runs=[TextRun(text=original_text, formatting=RunFormatting())],
                    formatting=ParagraphFormatting(),
                )
            ],
        )

        translations = {"Original": "Modified"}
        translator = ManualTranslator(translations, word_level=True)

        translated = translate_document(doc, translator, "en", "de")

        # Original should be unchanged
        assert doc.preamble_paragraphs[0].runs[0].text == original_text
        # Translated should be changed
        assert translated.preamble_paragraphs[0].runs[0].text == "Modified"

    def test_translate_document_complex(self):
        """Test translation of complex document with all features."""
        doc = Document(
            metadata=DocumentMetadata(
                line_numbering=LineNumbering(enabled=True),
                page_settings=PageSettings(),
            ),
            preamble_paragraphs=[
                Paragraph(
                    runs=[
                        TextRun(text="Prolog", formatting=RunFormatting()),
                    ],
                    formatting=ParagraphFormatting(),
                )
            ],
            sections=[
                Section(
                    header=Paragraph(
                        runs=[
                            TextRun(text="Teil Eins", formatting=RunFormatting(bold=True)),
                        ],
                        formatting=ParagraphFormatting(),
                        is_header=True,
                    ),
                    paragraphs=[
                        Paragraph(
                            runs=[
                                TextRun(text="Absatz", formatting=RunFormatting()),
                                TextRun(text=" ", formatting=RunFormatting()),
                                TextRun(text="mit", formatting=RunFormatting()),
                                TextRun(
                                    text="1",
                                    formatting=RunFormatting(is_superscript=True),
                                ),
                            ],
                            formatting=ParagraphFormatting(),
                        ),
                    ],
                ),
            ],
        )

        translations = {
            "Prolog": "Prologue",
            "Teil Eins": "Part One",
            "Absatz": "Paragraph",
            "mit": "with",
        }
        translator = ManualTranslator(translations, word_level=True)

        translated = translate_document(doc, translator, "de", "en")

        # Check preamble
        assert translated.preamble_paragraphs[0].runs[0].text == "Prologue"

        # Check section header
        assert translated.sections[0].header.runs[0].text == "Part One"

        # Check body with mixed content
        assert translated.sections[0].paragraphs[0].runs[0].text == "Paragraph"
        assert translated.sections[0].paragraphs[0].runs[1].text == " "  # Whitespace run
        assert translated.sections[0].paragraphs[0].runs[2].text == "with"
        # Superscript should not be translated
        assert translated.sections[0].paragraphs[0].runs[3].text == "1"
        assert translated.sections[0].paragraphs[0].runs[3].formatting.is_superscript

    def test_translate_document_whitespace_runs_skipped(self):
        """Should skip whitespace-only runs from translation."""
        doc = Document(
            metadata=DocumentMetadata(
                line_numbering=LineNumbering(),
                page_settings=PageSettings(),
            ),
            sections=[],
            preamble_paragraphs=[
                Paragraph(
                    runs=[
                        TextRun(text="Word1", formatting=RunFormatting()),
                        TextRun(text="   ", formatting=RunFormatting()),
                        TextRun(text="Word2", formatting=RunFormatting()),
                    ],
                    formatting=ParagraphFormatting(),
                )
            ],
        )

        translations = {
            "Word1": "TRANSLATED1",
            "   ": "SHOULD_NOT_TRANSLATE",
            "Word2": "TRANSLATED2",
        }
        translator = ManualTranslator(translations, word_level=True)

        translated = translate_document(doc, translator, "en", "de")

        # Whitespace run should remain unchanged
        assert translated.preamble_paragraphs[0].runs[1].text == "   "
        assert translated.preamble_paragraphs[0].runs[0].text == "TRANSLATED1"
        assert translated.preamble_paragraphs[0].runs[2].text == "TRANSLATED2"


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
