import os
import sys
from unittest.mock import MagicMock, patch

import pytest

sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../../")))

from GramAddict.core.goap import PathMemory


class FakePoint:
    def __init__(self, payload):
        self.payload = payload


@pytest.fixture
def mock_qdrant_base():
    with patch("GramAddict.core.qdrant_memory.QdrantBase") as mock:
        instance = mock.return_value
        instance.is_connected = True
        instance.collection_name = "goap_paths_v1"
        instance.client = MagicMock()
        instance._get_embedding.return_value = [0.1] * 768
        yield instance


def test_path_overwrites_on_failure(mock_qdrant_base):
    """
    TDD Case: If a success path exists, but then a failure occurs,
    the failure should overwrite the success (or at least be the
    recalled path) because they share the same seed.
    """
    pm = PathMemory()
    pm._db = mock_qdrant_base  # Inject our mock

    goal = "open messages"
    start = "home_feed"

    # 1. Learn success
    pm.learn_path(goal, start, [{"action": "tap messages tab"}], True)

    # Verify upsert seed
    # With our fix, it should be simply "open messages|home_feed"
    args, kwargs = mock_qdrant_base.upsert_point.call_args
    assert args[0] == f"{goal}|{start}"
    assert args[1]["success"] is True

    # 2. Learn failure (same goal, same start)
    # This should call upsert_point with the SAME seed, thus overwriting
    pm.learn_path(goal, start, [{"action": "tap reels tab"}] * 15, False)

    args, kwargs = mock_qdrant_base.upsert_point.call_args
    assert args[0] == f"{goal}|{start}"
    assert args[1]["success"] is False
    assert args[1]["step_count"] == 15

    # 3. Recall
    # We mock return from Qdrant - only one item (the latest)
    query_result = MagicMock()
    query_result.points = [FakePoint(args[1])]  # The failure payload
    mock_qdrant_base.client.query_points.return_value = query_result

    recalled = pm.recall_path(goal, start)

    # Should be None because the latest entry has success=False
    assert recalled is None
