"""Tests for AI delta response parsing and action-type prompt dispatch."""
from app.core.ai_chat_service import _parse_delta, _build_action_prompt, _find_node_by_id


def test_parse_delta_from_response():
    """Service extracts [DELTA] markers from AI responses."""
    response = '''Here's a new branch for that node.

[DELTA]
{"action": "add", "target_node_id": "check-dns", "nodes": [{"id": "verify-dns-server", "type": "decision", "question": "Is the DNS server responding?"}], "explanation": "Added DNS verification branch"}
[/DELTA]

Let me know if you'd like to adjust this.'''

    parsed = _parse_delta(response)
    assert parsed is not None
    assert parsed["action"] == "add"
    assert parsed["target_node_id"] == "check-dns"
    assert len(parsed["nodes"]) == 1


def test_parse_delta_none_when_absent():
    """Returns None when no delta marker present."""
    response = "Sure, I can explain that node. It checks connectivity."
    parsed = _parse_delta(response)
    assert parsed is None


def test_parse_delta_with_markdown_fences():
    """Handles delta JSON wrapped in markdown code fences."""
    response = '''[DELTA]
```json
{"action": "modify", "target_node_id": "node-1", "nodes": [{"id": "node-1", "type": "action", "title": "Updated"}], "explanation": "Modified title"}
```
[/DELTA]'''
    parsed = _parse_delta(response)
    assert parsed is not None
    assert parsed["action"] == "modify"


def test_parse_delta_invalid_json():
    """Returns None for invalid JSON inside delta markers."""
    response = "[DELTA]not valid json[/DELTA]"
    parsed = _parse_delta(response)
    assert parsed is None


def test_build_action_prompt_generate_branch():
    """Generate branch action includes focal node context."""
    tree = {
        "id": "root",
        "type": "decision",
        "question": "Is the server up?",
        "children": [],
        "options": [],
    }
    prompt = _build_action_prompt(
        action_type="generate_branch",
        focal_node_id="root",
        tree_structure=tree,
        flow_type="troubleshooting",
    )
    assert "root" in prompt
    assert "generate" in prompt.lower() or "branch" in prompt.lower()


def test_build_action_prompt_open_chat():
    """Open chat action is general conversation."""
    prompt = _build_action_prompt(
        action_type="open_chat",
        focal_node_id=None,
        tree_structure={"id": "root", "type": "decision"},
        flow_type="troubleshooting",
    )
    assert isinstance(prompt, str)
    assert len(prompt) > 0


def test_find_node_by_id_root():
    """Finds root node."""
    tree = {"id": "root", "type": "decision", "children": []}
    assert _find_node_by_id(tree, "root") is not None


def test_find_node_by_id_nested():
    """Finds nested child node."""
    tree = {
        "id": "root",
        "type": "decision",
        "children": [
            {"id": "child-1", "type": "action", "children": []},
            {"id": "child-2", "type": "solution", "children": []},
        ],
    }
    found = _find_node_by_id(tree, "child-2")
    assert found is not None
    assert found["id"] == "child-2"


def test_find_node_by_id_not_found():
    """Returns None for non-existent node."""
    tree = {"id": "root", "type": "decision", "children": []}
    assert _find_node_by_id(tree, "nonexistent") is None


def test_find_node_by_id_in_steps():
    """Finds node in procedural steps array."""
    tree = {
        "steps": [
            {"id": "step-1", "type": "procedure_step"},
            {"id": "step-2", "type": "procedure_step"},
        ]
    }
    found = _find_node_by_id(tree, "step-2")
    assert found is not None
    assert found["id"] == "step-2"
