from io import BytesIO

from translate.storage import tmx

from . import test_base


class TestTMXUnit(test_base.TestTranslationUnit):
    UnitClass = tmx.tmxunit


class TestTMXUnitFromParsedString(TestTMXUnit):
    tmxsource = """<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE tmx
  SYSTEM 'tmx14.dtd'>
<tmx version="1.4">
        <header adminlang="en" creationtool="Translate Toolkit" creationtoolversion="1.0beta" datatype="PlainText" o-tmf="UTF-8" segtype="sentence" srclang="en"/>
        <body>
                <tu>
                        <tuv xml:lang="en">
                                <seg>Test String</seg>
                        </tuv>
                </tu>
        </body>
</tmx>"""

    def setup_method(self, method) -> None:
        store = tmx.tmxfile.parsestring(self.tmxsource)
        self.unit = store.units[0]

    def test_context(self) -> None:
        tmxunit = self.UnitClass("Sample source")
        assert tmxunit.getcontext() == ""
        tmxunit.setcontext("context info")
        assert tmxunit.getcontext() == "context info"


class TestTMXfile(test_base.TestTranslationStore):
    StoreClass = tmx.tmxfile

    @staticmethod
    def tmxparse(tmxsource):
        """Helper that parses tmx source without requiring files."""
        dummyfile = BytesIO(tmxsource)
        print(tmxsource)
        return tmx.tmxfile(dummyfile)

    def test_translate(self) -> None:
        tmxfile = tmx.tmxfile()
        assert tmxfile.translate("Anything") is None
        tmxfile.addtranslation(
            "A string of characters", "en", "'n String karakters", "af"
        )
        assert tmxfile.translate("A string of characters") == "'n String karakters"

    def test_addtranslation(self) -> None:
        """Tests that addtranslation() stores strings correctly."""
        tmxfile = tmx.tmxfile()
        tmxfile.addtranslation(
            "A string of characters", "en", "'n String karakters", "af"
        )
        newfile = self.tmxparse(bytes(tmxfile))
        print(bytes(tmxfile))
        assert newfile.translate("A string of characters") == "'n String karakters"

    def test_withcomment(self) -> None:
        """Tests that addtranslation() stores string's comments correctly."""
        tmxfile = tmx.tmxfile()
        tmxfile.addtranslation(
            "A string of chars", "en", "'n String karakters", "af", "comment"
        )
        newfile = self.tmxparse(bytes(tmxfile))
        print(bytes(tmxfile))
        assert newfile.findunit("A string of chars").getnotes() == "comment"

    def test_withnewlines(self) -> None:
        """Test addtranslation() with newlines."""
        tmxfile = tmx.tmxfile()
        tmxfile.addtranslation(
            "First line\nSecond line", "en", "Eerste lyn\nTweede lyn", "af"
        )
        newfile = self.tmxparse(bytes(tmxfile))
        print(bytes(tmxfile))
        assert newfile.translate("First line\nSecond line") == "Eerste lyn\nTweede lyn"

    def test_xmlentities(self) -> None:
        """Test that the xml entities '&' and '<'  are escaped correctly."""
        tmxfile = tmx.tmxfile()
        tmxfile.addtranslation("Mail & News", "en", "Nuus & pos", "af")
        tmxfile.addtranslation("Five < ten", "en", "Vyf < tien", "af")
        xmltext = bytes(tmxfile).decode("utf-8")
        print("The generated xml:")
        print(xmltext)
        assert tmxfile.translate("Mail & News") == "Nuus & pos"
        assert xmltext.index("Mail &amp; News")
        assert xmltext.find("Mail & News") == -1
        assert tmxfile.translate("Five < ten") == "Vyf < tien"
        assert xmltext.index("Five &lt; ten")
        assert xmltext.find("Five < ten") == -1

    def test_controls_cleaning(self) -> None:
        """Test addtranslation() with control chars."""
        tmxfile = tmx.tmxfile()
        tmxfile.addtranslation("Client Version:\x0314 %s", "en", "test one", "ar")
        tmxfile.addtranslation("Client Version:\n%s", "en", "test two", "ar")
        newfile = self.tmxparse(bytes(tmxfile))
        print(bytes(tmxfile))
        assert newfile.translate("Client Version:14 %s") == "test one"
        assert newfile.translate("Client Version:\n%s") == "test two"

    def test_context(self) -> None:
        store = self.StoreClass()
        unit = store.addsourceunit("Source text")
        unit.target = "Target text"
        unit.setcontext("Context text")
        store.addunit(unit)
        assert b"Context text" in (bytes(store))

        newsource = """<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE tmx
  SYSTEM 'tmx14.dtd'>
<tmx version="1.4">
        <header adminlang="en" creationtool="Translate Toolkit" creationtoolversion="1.0beta" datatype="PlainText" o-tmf="UTF-8" segtype="sentence" srclang="en"/>
        <body>
                <tu>
                        <prop type="x-context">Context text</prop>
                        <tuv xml:lang="en">
                                <seg>Test String</seg>
                        </tuv>
                </tu>
        </body>
</tmx>"""

        newstore = self.StoreClass().parsestring(newsource)
        assert newstore.units[0].getcontext() == "Context text"

    def test_note_order(self) -> None:
        """Test that notes appear before tuv elements as per TMX DTD."""
        store = self.StoreClass()
        unit = store.addsourceunit("Test")
        unit.target = "Prueba"
        unit.addnote("Test note")

        # Get the order of elements
        element_tags = [
            child.tag.split("}")[1] if "}" in child.tag else child.tag
            for child in unit.xmlelement
        ]

        # Note should come before tuv elements
        assert "note" in element_tags
        assert "tuv" in element_tags
        note_index = element_tags.index("note")
        first_tuv_index = element_tags.index("tuv")
        assert note_index < first_tuv_index, (
            "note element should appear before tuv elements"
        )

    def test_prop_and_note_order(self) -> None:
        """Test that notes and props appear before tuv elements as per TMX DTD."""
        store = self.StoreClass()
        unit = store.addsourceunit("Test")
        unit.target = "Prueba"
        unit.addnote("Test note")
        unit.setcontext("test-context")

        # Get the order of elements
        element_tags = [
            child.tag.split("}")[1] if "}" in child.tag else child.tag
            for child in unit.xmlelement
        ]

        # Both note and prop should come before tuv elements
        assert "note" in element_tags
        assert "prop" in element_tags
        assert "tuv" in element_tags

        note_index = element_tags.index("note")
        prop_index = element_tags.index("prop")
        first_tuv_index = element_tags.index("tuv")

        assert note_index < first_tuv_index, (
            "note element should appear before tuv elements"
        )
        assert prop_index < first_tuv_index, (
            "prop element should appear before tuv elements"
        )
