from __future__ import annotations

from pathlib import Path

import pytest

from rimpack.core.mods.load_folders import (
    LoadFolderEntry,
    LoadFolders,
    LoadFoldersXmlError,
    VersionedLoadFolderEntries,
    load_load_folders_xml,
    parse_load_folders_xml,
)


def test_parse_load_folders_with_conditions() -> None:
    load_folders = parse_load_folders_xml(
        """\
<?xml version="1.0" encoding="utf-8"?>
<loadFolders>
  <v1.4>
    <li>Common</li>
    <li IfModActive="brrainz.harmony">Harmony</li>
    <li IfModNotActive="ludeon.rimworld">Fallback</li>
    <li IfModActiveAll="mod.one, mod.two">Combined</li>
    <li IfModActiveAny="mod.three, mod.four">AnyCombined</li>
  </v1.4>
  <v1.5>
    <li>Current</li>
  </v1.5>
</loadFolders>
""",
    )

    assert load_folders == LoadFolders(
        versions=(
            VersionedLoadFolderEntries(
                version="v1.4",
                entries=(
                    LoadFolderEntry(path="Common"),
                    LoadFolderEntry(path="Harmony", if_mod_active="brrainz.harmony"),
                    LoadFolderEntry(path="Fallback", if_mod_not_active="ludeon.rimworld"),
                    LoadFolderEntry(
                        path="Combined",
                        if_mod_active_all=("mod.one", "mod.two"),
                    ),
                    LoadFolderEntry(
                        path="AnyCombined",
                        if_mod_active_any=("mod.three", "mod.four"),
                    ),
                ),
            ),
            VersionedLoadFolderEntries(
                version="v1.5",
                entries=(LoadFolderEntry(path="Current"),),
            ),
        ),
    )


def test_load_load_folders_xml_from_path() -> None:
    path = Path("tests") / "__tmp_load_folders.xml"
    try:
        _ = path.write_text(
            """\
<loadFolders>
  <v1.5>
    <li>Defs</li>
  </v1.5>
</loadFolders>
""",
            encoding="utf-8",
        )

        load_folders = load_load_folders_xml(path)

        assert load_folders.versions[0].entries[0].path == "Defs"
    finally:
        path.unlink(missing_ok=True)


def test_reject_invalid_root_tag() -> None:
    with pytest.raises(LoadFoldersXmlError, match="expected root tag 'loadFolders'"):
        _ = parse_load_folders_xml("<notLoadFolders />")


def test_accept_capitalized_root_tag() -> None:
    load_folders = parse_load_folders_xml(
        """\
<LoadFolders>
  <v1.6>
    <li>Defs</li>
  </v1.6>
</LoadFolders>
""",
    )

    assert load_folders == LoadFolders(
        versions=(
            VersionedLoadFolderEntries(
                version="v1.6",
                entries=(LoadFolderEntry(path="Defs"),),
            ),
        ),
    )


def test_reject_empty_document() -> None:
    with pytest.raises(LoadFoldersXmlError, match="must contain at least one version"):
        _ = parse_load_folders_xml("<loadFolders />")


def test_reject_non_li_children_under_version() -> None:
    with pytest.raises(LoadFoldersXmlError, match="must only contain 'li' elements"):
        _ = parse_load_folders_xml(
            """\
<loadFolders>
  <v1.5>
    <folder>Defs</folder>
  </v1.5>
</loadFolders>
""",
        )


def test_ignore_blank_entries_and_empty_versions() -> None:
    load_folders = parse_load_folders_xml(
        """\
<loadFolders>
  <v1.0>
    <li></li>
  </v1.0>
  <v1.1>
    <li></li>
    <li>1.1</li>
  </v1.1>
</loadFolders>
""",
    )

    assert load_folders == LoadFolders(
        versions=(
            VersionedLoadFolderEntries(
                version="v1.1",
                entries=(LoadFolderEntry(path="1.1"),),
            ),
        ),
    )


def test_parse_nested_conditional_entry() -> None:
    load_folders = parse_load_folders_xml(
        """\
<loadFolders>
  <v1.6>
    <li IfModActive="outer.mod">
      <li IfModNotActive="inner.blocker">Defs</li>
    </li>
  </v1.6>
</loadFolders>
""",
    )

    assert load_folders == LoadFolders(
        versions=(
            VersionedLoadFolderEntries(
                version="v1.6",
                entries=(
                    LoadFolderEntry(
                        path="Defs",
                        if_mod_active="outer.mod",
                        if_mod_not_active="inner.blocker",
                    ),
                ),
            ),
        ),
    )


def test_reject_empty_entry_when_attributes_present() -> None:
    with pytest.raises(
        LoadFoldersXmlError,
        match="load folder entries with attributes must not be empty",
    ):
        _ = parse_load_folders_xml(
            """\
<loadFolders>
  <v1.5>
    <li IfModActive="brrainz.harmony"></li>
  </v1.5>
</loadFolders>
""",
        )


def test_reject_unsupported_entry_attributes() -> None:
    with pytest.raises(LoadFoldersXmlError, match="unsupported attribute"):
        _ = parse_load_folders_xml(
            """\
<loadFolders>
  <v1.5>
    <li IfUnknown="x">Defs</li>
  </v1.5>
</loadFolders>
""",
        )
