import time
from unittest.mock import MagicMock, patch

import pytest

from GramAddict.core.darwin_engine import DarwinEngine
from GramAddict.core.dojo_engine import DojoEngine
from GramAddict.core.growth_brain import GrowthBrain
from GramAddict.core.q_nav_graph import QNavGraph

# Import under test
from GramAddict.core.qdrant_memory import (
    ContentMemoryDB,
    HeuristicMemoryDB,
    NavigationMemoryDB,
    ParasocialCRMDB,
    PersonaMemoryDB,
)
from GramAddict.core.resonance_engine import ResonanceEngine
from GramAddict.core.swarm_protocol import SwarmProtocol


@pytest.fixture
def mock_PointStruct():
    with patch("GramAddict.core.qdrant_memory.PointStruct") as mock:
        yield mock


@pytest.fixture
def mock_qdrant(mock_PointStruct):
    with patch("GramAddict.core.qdrant_memory.QdrantClient") as MockClient:
        client_instance = MockClient.return_value
        client_instance.collection_exists.return_value = True
        yield client_instance


# --- ORIGINAL CORE AUDIT ---


def test_parasocial_crm_logging(mock_qdrant, mock_PointStruct):
    """Verify that CRM interaction logging actually attempts to persist to Qdrant."""
    crm = ParasocialCRMDB()
    crm.client = mock_qdrant
    with patch.object(ParasocialCRMDB, "_get_embedding", return_value=[0.1] * 1536):
        crm.log_interaction("test_user_alpha", "like")

    assert mock_qdrant.upsert.called
    kwargs = mock_PointStruct.call_args[1]
    assert kwargs["payload"]["username"] == "test_user_alpha"
    assert kwargs["payload"]["interactions"][0]["type"] == "like"


def test_darwin_reward_signaling(mock_qdrant, mock_PointStruct):
    """Verify that Darwin Engine correctly records session rewards for reinforcement learning."""
    engine = DarwinEngine("test_bot")
    engine.client = mock_qdrant
    engine.current_behavior = {"initial_dwell_sec": 4.5}
    engine.emit_reward_signal(followers_gained=5, block_warnings_seen=0)

    assert mock_qdrant.upsert.called
    kwargs = mock_PointStruct.call_args[1]
    assert kwargs["payload"]["reward"] == 5


def test_swarm_pheromone_emission(mock_qdrant, mock_PointStruct):
    """Verify that Swarm Protocol shares UI state outcomes with the fleet."""
    swarm = SwarmProtocol("test_bot")
    swarm.client = mock_qdrant
    swarm.emit_pheromone("feed_scroll_A", "success")

    assert mock_qdrant.upsert.called
    kwargs = mock_PointStruct.call_args[1]
    assert kwargs["payload"]["path_hash"] == "feed_scroll_A"


def test_dojo_background_learning(mock_qdrant, mock_PointStruct):
    """Verify that Dojo Engine processes snapshots and updates the heuristic memory."""
    device = MagicMock()
    dojo = DojoEngine(device)
    dojo.db.client = mock_qdrant
    with patch.object(dojo.compiler, "generate_heuristic", return_value={"rule_type": "regex", "pattern": ".*"}):
        with patch.object(HeuristicMemoryDB, "_get_embedding", return_value=[0.1] * 1536):
            dojo.start()
            dojo.submit_snapshot("test_button_intent", "<xml/>", "Tap the like button")
            start = time.time()
            while mock_qdrant.upsert.call_count == 0 and time.time() - start < 3.0:
                time.sleep(0.1)
            dojo.stop()

    assert mock_qdrant.upsert.called
    kwargs = mock_PointStruct.call_args[1]
    assert kwargs["payload"]["intent"] == "test_button_intent"


# --- EXTENDED ULTRA-AUDIT (PHASE 2) ---


def test_growth_brain_persona_learning(mock_qdrant, mock_PointStruct):
    """Verify that GrowthBrain persists persona insights derived from interactions."""
    brain = GrowthBrain("test_user")
    brain.persona_memory.client = mock_qdrant  # Inject client into the wrapped DB

    outcomes = [{"username": "niche_influencer", "action": "like", "resonance": 0.9}]
    with patch.object(PersonaMemoryDB, "_get_embedding", return_value=[0.1] * 1536):
        brain.refine_persona(outcomes)

    assert mock_qdrant.upsert.called
    kwargs = mock_PointStruct.call_args[1]
    assert "High-resonance" in kwargs["payload"]["insight"]


def test_resonance_oracle_cross_talk(mock_qdrant, mock_PointStruct):
    """Verify that ResonanceEngine evaluation triggers both ContentMemory and ParasocialCRM updates."""
    crm = ParasocialCRMDB()
    crm.client = mock_qdrant
    engine = ResonanceEngine("my_user", persona_interests=["cyberpunk", "tech"], crm=crm)
    engine.content_memory.client = mock_qdrant

    post = {"username": "cyber_artist", "description": "New neon artwork #cyberpunk", "caption": ""}

    with (
        patch.object(ContentMemoryDB, "_get_embedding", return_value=[0.1] * 1536),
        patch.object(ParasocialCRMDB, "_get_embedding", return_value=[0.1] * 1536),
        patch.object(NavigationMemoryDB, "_get_embedding", return_value=[0.1] * 1536),
        patch.object(engine, "_cosine_similarity", return_value=0.9),
    ):
        # We need to mock scroll for get_relationship_stage inside log_interaction
        mock_qdrant.scroll.return_value = ([], None)

        score = engine.calculate_resonance(post)
        assert score > 0.7

    # Should call upsert twice: 1 for content_memory, 1 for crm (inside ResonanceEngine)
    assert mock_qdrant.upsert.call_count >= 2

    # Verify ContentMemory storage
    calls = [mock_PointStruct.call_args_list[i][1] for i in range(len(mock_PointStruct.call_args_list))]
    content_storage = any("classification" in c["payload"] for c in calls)
    crm_storage = any("stage" in c["payload"] for c in calls)

    assert content_storage, "ResonanceEngine failed to cache evaluation in ContentMemory!"
    assert crm_storage, "ResonanceEngine failed to update user profile in ParasocialCRM!"


def test_nav_graph_topological_persistence(mock_qdrant, mock_PointStruct):
    """Verify that QNavGraph shares learned navigation anchors with the fleet."""
    device = MagicMock()
    graph = QNavGraph(device)
    graph.nav_memory.client = mock_qdrant

    # Simulate discovering a transition
    graph.nav_memory.store_transition("ExploreFeed", "tap_home_tab", "HomeFeed")

    assert mock_qdrant.upsert.called
    kwargs = mock_PointStruct.call_args[1]
    assert kwargs["payload"]["from"] == "ExploreFeed"
    assert kwargs["payload"]["action"] == "tap_home_tab"
    assert kwargs["payload"]["to"] == "HomeFeed"
