"""Tests for MERGE clause."""

import pytest
import networkx as nx

from nxcypher import NXCypher


class TestMergeCreates:
    """Tests for MERGE creating new nodes."""

    def test_merge_creates_new_node(self):
        """MERGE creates a new node when pattern doesn't exist."""
        host = nx.MultiDiGraph()
        host.add_node("Existing", name="Existing")
        initial_count = host.number_of_nodes()

        qry = """
        MERGE (n:Person {name: "Alice"})
        """
        NXCypher(host).run(qry)
        # Should create new node
        assert host.number_of_nodes() == initial_count + 1
        assert len([n for n in host.nodes() if host.nodes[n].get("name") == "Alice"]) == 1

    def test_merge_creates_with_labels(self):
        """MERGE creates a node with labels."""
        host = nx.MultiDiGraph()

        qry = """
        MERGE (n:Person {name: "Bob"})
        """
        NXCypher(host).run(qry)
        # Find the created node
        for node_id, data in host.nodes(data=True):
            if data.get("name") == "Bob":
                assert "Person" in data.get("__labels__", set())
                break
        else:
            pytest.fail("Node not created")


class TestMergeMatches:
    """Tests for MERGE matching existing nodes."""

    def test_merge_matches_existing_node(self):
        """MERGE matches when node already exists."""
        host = nx.MultiDiGraph()
        host.add_node("Alice", __labels__={"Person"}, name="Alice")

        initial_count = host.number_of_nodes()

        qry = """
        MERGE (n:Person {name: "Alice"})
        """
        NXCypher(host).run(qry)
        # Should not create new node
        assert host.number_of_nodes() == initial_count

    def test_merge_matches_by_properties(self):
        """MERGE matches nodes by properties."""
        host = nx.MultiDiGraph()
        host.add_node("Alice", name="Alice", age=30)

        initial_count = host.number_of_nodes()

        qry = """
        MERGE (n {name: "Alice"})
        """
        NXCypher(host).run(qry)
        assert host.number_of_nodes() == initial_count


class TestMergeOnCreate:
    """Tests for MERGE ON CREATE SET."""

    def test_merge_on_create_sets_property(self):
        """MERGE ON CREATE SET only applies when creating."""
        host = nx.MultiDiGraph()

        qry = """
        MERGE (n:Person {name: "Alice"})
        ON CREATE SET n.created = true
        """
        NXCypher(host).run(qry)
        # Find the created node
        for node_id, data in host.nodes(data=True):
            if data.get("name") == "Alice":
                assert data.get("created") == True
                break
        else:
            pytest.fail("Node not created")

    def test_merge_on_create_not_applied_when_matching(self):
        """ON CREATE SET is not applied when matching existing node."""
        host = nx.MultiDiGraph()
        host.add_node("Alice", __labels__={"Person"}, name="Alice")

        qry = """
        MERGE (n:Person {name: "Alice"})
        ON CREATE SET n.created = true
        """
        NXCypher(host).run(qry)
        # ON CREATE should not apply
        assert host.nodes["Alice"].get("created") is None


class TestMergeOnMatch:
    """Tests for MERGE ON MATCH SET."""

    def test_merge_on_match_sets_property(self):
        """MERGE ON MATCH SET applies when matching existing."""
        host = nx.MultiDiGraph()
        host.add_node("Alice", __labels__={"Person"}, name="Alice")

        qry = """
        MERGE (n:Person {name: "Alice"})
        ON MATCH SET n.accessed = true
        """
        NXCypher(host).run(qry)
        assert host.nodes["Alice"].get("accessed") == True

    def test_merge_on_match_not_applied_when_creating(self):
        """ON MATCH SET is not applied when creating new node."""
        host = nx.MultiDiGraph()

        qry = """
        MERGE (n:Person {name: "Alice"})
        ON MATCH SET n.accessed = true
        """
        NXCypher(host).run(qry)
        # Find the created node
        for node_id, data in host.nodes(data=True):
            if data.get("name") == "Alice":
                assert data.get("accessed") is None
                break


class TestMergeCombined:
    """Tests for MERGE with both ON CREATE and ON MATCH."""

    def test_merge_both_on_create_and_on_match(self):
        """MERGE with both ON CREATE SET and ON MATCH SET."""
        host = nx.MultiDiGraph()

        # First merge - should create
        qry1 = """
        MERGE (n:Person {name: "Alice"})
        ON CREATE SET n.created = true
        ON MATCH SET n.accessed = true
        """
        NXCypher(host).run(qry1)

        # Find the created node
        alice_id = None
        for node_id, data in host.nodes(data=True):
            if data.get("name") == "Alice":
                alice_id = node_id
                assert data.get("created") == True
                assert data.get("accessed") is None
                break

        # Second merge - should match
        qry2 = """
        MERGE (n:Person {name: "Alice"})
        ON CREATE SET n.created = true
        ON MATCH SET n.accessed = true
        """
        NXCypher(host).run(qry2)

        # Check ON MATCH SET was applied
        assert host.nodes[alice_id].get("accessed") == True
