"""Tests for dialogue tree data model and TOML loading."""

import tempfile
from pathlib import Path

import pytest

from mudlib.dialogue import (
    load_all_dialogues,
    load_dialogue,
)


def test_load_dialogue_from_toml():
    """Load a dialogue tree from TOML with correct structure."""
    toml_content = """
npc_name = "guard"
root_node = "greeting"

[nodes.greeting]
text = "Halt! State your business."

[[nodes.greeting.choices]]
text = "I'm just passing through."
next_node = "passing"

[[nodes.greeting.choices]]
text = "I have a delivery."
next_node = "delivery"

[nodes.passing]
text = "Move along then, quickly."

[nodes.delivery]
text = "Leave it by the gate."
"""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
        f.write(toml_content)
        f.flush()
        path = Path(f.name)

    try:
        tree = load_dialogue(path)
        assert tree.npc_name == "guard"
        assert tree.root_node == "greeting"
        assert len(tree.nodes) == 3

        # Check greeting node
        greeting = tree.nodes["greeting"]
        assert greeting.id == "greeting"
        assert greeting.text == "Halt! State your business."
        assert len(greeting.choices) == 2
        assert greeting.choices[0].text == "I'm just passing through."
        assert greeting.choices[0].next_node == "passing"
        assert greeting.choices[1].text == "I have a delivery."
        assert greeting.choices[1].next_node == "delivery"

        # Check terminal nodes
        passing = tree.nodes["passing"]
        assert passing.id == "passing"
        assert passing.text == "Move along then, quickly."
        assert len(passing.choices) == 0

        delivery = tree.nodes["delivery"]
        assert delivery.id == "delivery"
        assert delivery.text == "Leave it by the gate."
        assert len(delivery.choices) == 0
    finally:
        path.unlink()


def test_node_traversal():
    """Follow choices from root to next nodes."""
    toml_content = """
npc_name = "merchant"
root_node = "greeting"

[nodes.greeting]
text = "Welcome to my shop!"

[[nodes.greeting.choices]]
text = "What do you sell?"
next_node = "wares"

[nodes.wares]
text = "Potions and scrolls, finest in town."
"""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
        f.write(toml_content)
        f.flush()
        path = Path(f.name)

    try:
        tree = load_dialogue(path)
        current = tree.nodes[tree.root_node]
        assert current.text == "Welcome to my shop!"

        # Follow the first choice
        next_id = current.choices[0].next_node
        current = tree.nodes[next_id]
        assert current.text == "Potions and scrolls, finest in town."
    finally:
        path.unlink()


def test_terminal_node_ends_conversation():
    """Nodes with no choices are terminal."""
    toml_content = """
npc_name = "beggar"
root_node = "plea"

[nodes.plea]
text = "Spare a coin?"

[[nodes.plea.choices]]
text = "Here you go."
next_node = "thanks"

[nodes.thanks]
text = "Bless you, kind soul."
"""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
        f.write(toml_content)
        f.flush()
        path = Path(f.name)

    try:
        tree = load_dialogue(path)
        thanks = tree.nodes["thanks"]
        assert len(thanks.choices) == 0  # Terminal node
    finally:
        path.unlink()


def test_choice_with_condition():
    """Choices can have optional conditions."""
    toml_content = """
npc_name = "gatekeeper"
root_node = "greeting"

[nodes.greeting]
text = "The gate is locked."

[[nodes.greeting.choices]]
text = "I have the key."
next_node = "unlock"
condition = "has_item:gate_key"

[nodes.unlock]
text = "Very well, pass through."
"""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
        f.write(toml_content)
        f.flush()
        path = Path(f.name)

    try:
        tree = load_dialogue(path)
        greeting = tree.nodes["greeting"]
        choice = greeting.choices[0]
        assert choice.condition == "has_item:gate_key"
        assert choice.next_node == "unlock"
    finally:
        path.unlink()


def test_node_with_action():
    """Nodes can have optional actions."""
    toml_content = """
npc_name = "quest_giver"
root_node = "offer"

[nodes.offer]
text = "Will you help me find my lost cat?"

[[nodes.offer.choices]]
text = "I'll do it."
next_node = "accept"

[nodes.accept]
text = "Thank you! Here's a map."
action = "give_item:cat_map"
"""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
        f.write(toml_content)
        f.flush()
        path = Path(f.name)

    try:
        tree = load_dialogue(path)
        accept = tree.nodes["accept"]
        assert accept.action == "give_item:cat_map"
    finally:
        path.unlink()


def test_load_all_dialogues():
    """Load multiple dialogue files from a directory."""
    guard_content = """
npc_name = "guard"
root_node = "greeting"

[nodes.greeting]
text = "Halt!"
"""
    merchant_content = """
npc_name = "merchant"
root_node = "greeting"

[nodes.greeting]
text = "Welcome!"
"""
    with tempfile.TemporaryDirectory() as tmpdir:
        tmppath = Path(tmpdir)
        (tmppath / "guard.toml").write_text(guard_content)
        (tmppath / "merchant.toml").write_text(merchant_content)

        trees = load_all_dialogues(tmppath)
        assert len(trees) == 2
        assert "guard" in trees
        assert "merchant" in trees
        assert trees["guard"].npc_name == "guard"
        assert trees["merchant"].npc_name == "merchant"


def test_missing_root_node():
    """Raise error if root_node doesn't exist in nodes."""
    toml_content = """
npc_name = "broken"
root_node = "nonexistent"

[nodes.greeting]
text = "Hello."
"""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
        f.write(toml_content)
        f.flush()
        path = Path(f.name)

    try:
        with pytest.raises(ValueError, match="root_node.*not found"):
            load_dialogue(path)
    finally:
        path.unlink()


def test_missing_next_node():
    """Raise error if a choice references a non-existent node."""
    toml_content = """
npc_name = "broken"
root_node = "greeting"

[nodes.greeting]
text = "Hello."

[[nodes.greeting.choices]]
text = "Goodbye."
next_node = "nonexistent"
"""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".toml", delete=False) as f:
        f.write(toml_content)
        f.flush()
        path = Path(f.name)

    try:
        with pytest.raises(ValueError, match="next_node.*not found"):
            load_dialogue(path)
    finally:
        path.unlink()
