from io import BytesIO

from translate.convert import ts2po

from . import test_convert


class TestTS2PO:
    @staticmethod
    def ts2po(tssource):
        converter = ts2po.ts2po()
        tsfile = BytesIO(tssource.encode())
        outputpo = converter.convertfile(tsfile)
        print("The generated po:")
        print(bytes(outputpo))
        return outputpo

    def test_blank(self) -> None:
        """Tests blank conversion."""
        tssource = """<!DOCTYPE TS><TS>
<context>
    <name>MainWindowBase</name>
    <message>
        <source>Project:</source>
        <translation type="unfinished"></translation>
    </message>
</context>
</TS>
"""
        pofile = self.ts2po(tssource)
        assert len(pofile.units) == 2
        assert pofile.units[1].source == "Project:"
        assert pofile.units[1].target == ""
        assert pofile.units[1].getlocations()[0].startswith("MainWindowBase")
        assert not pofile.units[1].isfuzzy()

    def test_basic(self) -> None:
        """Tests basic conversion."""
        tssource = """<!DOCTYPE TS><TS>
<context>
    <name>AboutDialog</name>
    <message>
        <source>&amp;About</source>
        <translation>&amp;Giới thiệu</translation>
    </message>
</context>
</TS>
"""
        pofile = self.ts2po(tssource)
        assert len(pofile.units) == 2
        assert pofile.units[1].source == "&About"
        assert pofile.units[1].target == "&Giới thiệu"
        assert pofile.units[1].getlocations()[0].startswith("AboutDialog")

    def test_unfinished(self) -> None:
        """Tests unfinished conversion."""
        tssource = """<!DOCTYPE TS><TS>
<context>
    <name>MainWindowBase</name>
    <message>
        <source>Project:</source>
        <translation type="unfinished">Projek vergardering</translation>
    </message>
</context>
</TS>
"""
        pofile = self.ts2po(tssource)
        assert len(pofile.units) == 2
        assert pofile.units[1].source == "Project:"
        assert pofile.units[1].target == "Projek vergardering"
        assert pofile.units[1].getlocations()[0].startswith("MainWindowBase")
        assert pofile.units[1].isfuzzy()

    def test_multiline(self) -> None:
        """Tests multiline message conversion."""
        tssource = """<!DOCTYPE TS><TS>
<context>
    <name>@default</name>
    <message>
        <source>Source with
new line</source>
        <translation>Test with
new line</translation>
    </message>
</context>
</TS>
"""
        pofile = self.ts2po(tssource)
        assert len(pofile.units) == 2
        assert pofile.units[1].source == "Source with\nnew line"
        assert pofile.units[1].target == "Test with\nnew line"
        assert pofile.units[1].getlocations()[0].startswith("@default")

    def test_obsolete(self) -> None:
        """Test the handling of obsolete TS entries."""
        tssource = """<!DOCTYPE TS><TS>
<context>
    <name>Obsoleted</name>
    <message>
        <source>Failed</source>
        <translation type="obsolete">Mislukt</translation>
    </message>
</context>
</TS>
"""
        pofile = self.ts2po(tssource)
        assert pofile.units[1].getnotes("developer") == "(obsolete)"
        # Test that we aren't following the old style
        assert "_ OBSOLETE" not in pofile.units[1].getnotes()

    def test_comment(self) -> None:
        """Test that we can handle disambiguation identifiers."""
        # Example from https://www.gnu.org/software/gettext/manual/html_node/Contexts.html
        tssource = """<!DOCTYPE TS><TS>
<context>
    <name>FileMenu</name>
    <message>
        <source>&amp;Open</source>
        <comment>Menu|File|</comment>
        <translation>&amp;Abrir</translation>
    </message>
</context>
</TS>
"""
        pofile = self.ts2po(tssource)
        assert pofile.units[1].getcontext() == "Menu|File|"

    def test_extracomment(self) -> None:
        """Test that we can handle '//:' comments from developers to translators."""
        tssource = """<!DOCTYPE TS><TS>
<context>
    <name>AboutDialog</name>
    <message>
        <source>&amp;About</source>
        <extracomment>Appears in the Help menu (on Windows and Linux) or the app menu (on macOS).</extracomment>
        <translation>&amp;Giới thiệu</translation>
    </message>
</context>
</TS>
"""
        pofile = self.ts2po(tssource)
        assert (
            pofile.units[1].getnotes()
            == "Appears in the Help menu (on Windows and Linux) or the app menu (on macOS)."
        )

    def test_emptycontext(self) -> None:
        """Test conversion with a leading empty context."""
        tssource = """<!DOCTYPE TS><TS>
<context>
    <name></name>
    <message>
        <source>Message to ignore</source>
        <translation>Missatge a ignorar</translation>
    </message>
</context>
<context>
    <name>ValidContext</name>
    <message>
        <source>Since we come from abroad, we thought the best thing we could do was to learn the local language and integrate ourselves.</source>
        <translation>Com que venim de fora vam pensar que el millor que podíem fer era aprendre la llengua d'aquí i integrar-nos.</translation>
    </message>
</context>
</TS>
"""
        pofile = self.ts2po(tssource)
        assert (
            pofile.units[1].source
            == "Since we come from abroad, we thought the best thing we could do was to learn the local language and integrate ourselves."
        )
        assert (
            pofile.units[1].target
            == "Com que venim de fora vam pensar que el millor que podíem fer era aprendre la llengua d'aquí i integrar-nos."
        )

    def test_plural(self) -> None:
        """Test the handling of plural forms in TS files."""
        tssource = """<!DOCTYPE TS><TS language="be">
<context>
    <name>ExampleTS</name>
    <message numerus="yes">
        <source>%d days ago</source>
        <translation><numerusform>%d dźeń tamu</numerusform><numerusform>%d dni tamu</numerusform><numerusform>%d dźon tamu</numerusform></translation>
    </message>
</context>
</TS>
"""
        pofile = self.ts2po(tssource)
        assert len(pofile.units) == 2
        # Check that plural forms are properly extracted
        assert pofile.units[1].hasplural()
        assert pofile.units[1].source.strings[0] == "%d days ago"
        assert pofile.units[1].source.strings[1] == "%d days ago"
        assert pofile.units[1].target.strings[0] == "%d dźeń tamu"
        assert pofile.units[1].target.strings[1] == "%d dni tamu"
        assert pofile.units[1].target.strings[2] == "%d dźon tamu"

    def test_plural_unfinished(self) -> None:
        """Test the handling of unfinished plural forms in TS files."""
        # spellchecker:off
        tssource = """<!DOCTYPE TS><TS language="be">
<context>
    <name>TestContext</name>
    <message numerus="yes">
        <source>%d items</source>
        <translation type="unfinished"><numerusform>%d element</numerusform><numerusform>%d elementy</numerusform></translation>
    </message>
</context>
</TS>
"""
        # spellchecker:on
        pofile = self.ts2po(tssource)
        assert len(pofile.units) == 2
        assert pofile.units[1].hasplural()
        assert pofile.units[1].isfuzzy()
        assert pofile.units[1].source.strings[0] == "%d items"
        assert pofile.units[1].source.strings[1] == "%d items"
        assert pofile.units[1].target.strings[0] == "%d element"
        assert pofile.units[1].target.strings[1] == "%d elementy"  # codespell:ignore


class TestTS2POCommand(test_convert.TestConvertCommand, TestTS2PO):
    """Tests running actual ts2po commands on files."""

    convertmodule = ts2po
    expected_options = [
        "--duplicates=DUPLICATESTYLE",
        "-P, --pot",
    ]
