from __future__ import annotations

from pathlib import Path

import pytest

from rimpack.core.modpack import (
    OrderingReference,
    OrderingRule,
    OrderingRulesDocument,
    OrderingTomlError,
    load_ordering_toml,
    parse_ordering_toml,
)


def test_parse_ordering_toml_with_supported_rule_shapes() -> None:
    document = parse_ordering_toml(
        """\
[[rules]]
type = "after"
mod = "packageid:my.ce.patch"
target = "packageid:ceteam.combatextended"
reason = "Compatibility patch loads after CE"

[[rules]]
type = "before"
mod = "packageid:Ludeon.RimWorld"
target = "packageid:Ludeon.RimWorld.Royalty"

[[rules]]
type = "after"
mod = "local:MyFork"
target = "steam:2009463077"
enabled = false
""",
    )

    assert document == OrderingRulesDocument(
        rules=(
            OrderingRule(
                rule_type="after",
                mod=OrderingReference(kind="packageid", value="my.ce.patch"),
                target=OrderingReference(
                    kind="packageid",
                    value="ceteam.combatextended",
                ),
                reason="Compatibility patch loads after CE",
                enabled=True,
            ),
            OrderingRule(
                rule_type="before",
                mod=OrderingReference(kind="packageid", value="Ludeon.RimWorld"),
                target=OrderingReference(
                    kind="packageid",
                    value="Ludeon.RimWorld.Royalty",
                ),
                enabled=True,
            ),
            OrderingRule(
                rule_type="after",
                mod=OrderingReference(kind="local", value="MyFork"),
                target=OrderingReference(kind="steam", value="2009463077"),
                enabled=False,
            ),
        ),
        source_text=(
            "[[rules]]\n"
            'type = "after"\n'
            'mod = "packageid:my.ce.patch"\n'
            'target = "packageid:ceteam.combatextended"\n'
            'reason = "Compatibility patch loads after CE"\n'
            "\n"
            "[[rules]]\n"
            'type = "before"\n'
            'mod = "packageid:Ludeon.RimWorld"\n'
            'target = "packageid:Ludeon.RimWorld.Royalty"\n'
            "\n"
            "[[rules]]\n"
            'type = "after"\n'
            'mod = "local:MyFork"\n'
            'target = "steam:2009463077"\n'
            "enabled = false\n"
        ),
    )


def test_parse_empty_ordering_toml_document() -> None:
    document = parse_ordering_toml("# no ordering overrides yet\n")

    assert document == OrderingRulesDocument(
        rules=(),
        source_text="# no ordering overrides yet\n",
    )


def test_load_ordering_toml_from_path() -> None:
    path = Path("tests") / "__tmp_ordering.toml"
    try:
        _ = path.write_text(
            """\
[[rules]]
type = "after"
mod = "packageid:Ludeon.RimWorld"
target = "packageid:Ludeon.RimWorld.Biotech"
""",
            encoding="utf-8",
        )

        document = load_ordering_toml(path)

        assert document.source_path == path
        assert document.rules == (
            OrderingRule(
                rule_type="after",
                mod=OrderingReference(kind="packageid", value="Ludeon.RimWorld"),
                target=OrderingReference(
                    kind="packageid",
                    value="Ludeon.RimWorld.Biotech",
                ),
                enabled=True,
            ),
        )
    finally:
        path.unlink(missing_ok=True)


def test_reject_invalid_ordering_rule_shapes() -> None:
    with pytest.raises(
        OrderingTomlError,
        match=r"rule #1 is missing required field 'target'",
    ):
        _ = parse_ordering_toml(
            """\
[[rules]]
type = "after"
mod = "packageid:brrainz.harmony"
""",
        )

    with pytest.raises(
        OrderingTomlError,
        match=r"rule #1 field 'type' must be 'before' or 'after'",
    ):
        _ = parse_ordering_toml(
            """\
[[rules]]
type = "around"
mod = "packageid:brrainz.harmony"
target = "steam:2009463077"
""",
        )

    with pytest.raises(
        OrderingTomlError,
        match=r"rule #1 field 'mod' has unsupported mod reference",
    ):
        _ = parse_ordering_toml(
            """\
[[rules]]
type = "after"
mod = "banana"
target = "steam:2009463077"
""",
        )

    with pytest.raises(
        OrderingTomlError,
        match=r"rule #1 field 'target' has unsupported mod reference",
    ):
        _ = parse_ordering_toml(
            """\
[[rules]]
type = "after"
mod = "packageid:brrainz.harmony"
target = "dlc:biotech"
""",
        )


def test_reject_unsupported_top_level_and_rule_fields() -> None:
    with pytest.raises(OrderingTomlError, match=r"unsupported top-level keys: metadata"):
        _ = parse_ordering_toml(
            """\
[metadata]
name = "bad"
""",
        )

    with pytest.raises(
        OrderingTomlError,
        match=r"rule #1 has unsupported fields: note",
    ):
        _ = parse_ordering_toml(
            """\
[[rules]]
type = "after"
mod = "packageid:brrainz.harmony"
target = "steam:2009463077"
note = "unsupported"
""",
        )
