"""
Graph Database Client for Neo4j operations.

This module provides functionality for:
- Mission DNA persistence and retrieval
- Context bullet management and scoring
- Infrastructure fact storage and retrieval
- Shared blackboard operations for multi-agent coordination
- Template management with migration support
"""

import datetime
import json
import uuid
from typing import Dict, Any, Optional, List, Literal, Union

import httpx
import yaml

from guardianhub import get_logger
from guardianhub.config.settings import settings
from guardianhub.models.common.common import KeywordList
from guardianhub.models.mission_blueprint import MissionBlueprintDNA
from guardianhub.models.template.suggestion import TemplateSchemaSuggestion

# Module logger
logger = get_logger(__name__)


class GraphDBClient:
    """
    Neo4j Graph Database Client for mission-critical operations.
    
    Provides high-level interface for:
    - Mission Blueprint DNA management
    - Context bullet curation and scoring
    - Infrastructure fact tracking
    - Multi-agent shared blackboard coordination
    """

    # ============================================================================
    # INITIALIZATION & CONFIGURATION
    # ============================================================================

    def __init__(self, poll_interval: int = 5, poll_timeout: int = 300) -> None:
        """Initialize the GraphDB client with configuration from settings."""
        self.api_url = settings.endpoints.get("GRAPH_DB_URL")
        self.headers = {"Accept": "application/json"}
        self.poll_interval = poll_interval
        self.poll_timeout = poll_timeout

        self.client = httpx.AsyncClient(
            headers=self.headers, 
            base_url=self.api_url, 
            timeout=self.poll_timeout + 60
        )
        logger.info(f"🔗 GraphDBClient initialized for URL: {self.api_url}")

    # ============================================================================
    # CORE HELPER METHODS
    # ============================================================================

    async def _execute_write_query(self, query: str, parameters: Dict[str, Any]) -> bool:
        """Execute a write query against the Graph DB service."""
        try:
            response = await self.client.post(
                "/execute-cypher-write",
                json={"query": query, "parameters": parameters},
                timeout=30.0
            )
            response.raise_for_status()
            result = response.json().get("status") == "success"
            if result:
                logger.debug(f"✅ Write query executed successfully")
            return result
        except Exception as e:
            logger.error(f"❌ GraphDB Write Error: {e}")
            return False

    async def _execute_read_query(self, query: str, parameters: Dict[str, Any]) -> List[Dict[str, Any]]:
        """Standardized Read: Returns the 'results' list from the Graph."""
        try:
            response = await self.client.post(
                "/query-cypher",
                json={"query": query, "parameters": parameters},
                timeout=30.0
            )
            response.raise_for_status()
            data = response.json()

            if data.get("status") == "success":
                return data.get("results", [])
            return []
        except Exception as e:
            logger.error(f"❌ GraphDB Read Error: {e}")
            return []

    # ============================================================================
    # MISSION DNA MANAGEMENT
    # ============================================================================

    async def save_mission_dna(self, dna: MissionBlueprintDNA, active_agent: Optional[str] = None) -> bool:
        """
        Anchors the MissionBlueprintDNA while establishing the Agent-Mission link.
        Supports the 'Mission Story' (What must be done) and
        the 'Agent Story' (Who is authorized/learning).
        """
        query = """
        // 1. MISSION STORY: MERGE the Blueprint (The Law)
        MERGE (m:MissionBlueprint {template_id: $template_id})
        SET m.mission_category = $mission_category,
            m.brief_summary = $brief_summary,
            m.mission_rationale = $mission_rationale,
            m.target_persona = $target_persona,
            m.auth_level_required = $auth_level_required,
            m.success_criteria = $success_criteria,
            m.safety_constraints = $safety_constraints,
            m.escalation_policy = $escalation_policy,
            m.estimated_blast_radius = $estimated_blast_radius,
            m.execution_timeout_seconds = $execution_timeout_seconds,
            m.briefing_template = $briefing_template,
            m.version = $version,
            m.last_evolved_at = datetime(),
            m.reflection_count = coalesce(m.reflection_count, 0) + $reflection_inc

        // 2. TOPOLOGICAL STORY: Link to the overarching Category
        MERGE (c:MissionCategory {name: $mission_category})
        MERGE (m)-[:BELONGS_TO]->(c)

        // 3. AGENT STORY: Link to the Authorized Specialist
        // This allows the Agent to 'own' its performance history for this DNA
        FOREACH (agent_name IN CASE WHEN $active_agent IS NOT NULL THEN [$active_agent] ELSE [] END |
            MERGE (a:AgentSpecialist {name: agent_name})
            MERGE (a)-[r:AUTHORIZED_FOR]->(m)
            SET r.last_used = datetime()
        )

        RETURN m.template_id as id
        """

        params = {
            "template_id": dna.template_id,
            "mission_category": dna.mission_category,
            "brief_summary": dna.brief_summary,
            "mission_rationale": dna.mission_rationale,
            "target_persona": dna.target_persona,
            "auth_level_required": dna.auth_level_required,
            "success_criteria": dna.success_criteria,
            "safety_constraints": dna.safety_constraints,
            "escalation_policy": dna.escalation_policy,
            "estimated_blast_radius": dna.estimated_blast_radius,
            "execution_timeout_seconds": dna.execution_timeout_seconds,
            "briefing_template": dna.briefing_template,
            "version": dna.version,
            "reflection_inc": 1 if dna.reflection_count > 0 else 0,
            "active_agent": active_agent  # 🎯 Connect the 'Who' to the 'What'
        }

        logger.info(f"⚓ Anchoring Dual-Story DNA: {dna.template_id} for Agent: {active_agent}")
        return await self._execute_write_query(query, params)

    # ============================================================================
    # TEMPLATE & DNA RETRIEVAL
    # ============================================================================

    # ============================================================================
    # MISSION DNA / BLUEPRINT RETRIEVAL
    # ============================================================================

    async def get_mission_dna(self, template_id: str) -> Optional[Dict[str, Any]]:
        """
        STRICT RETRIEVAL: Fetches only the Sovereign DNA for a Mission.
        Excludes formatting/schema templates to ensure governance integrity.
        """
        query = """
        MATCH (m:MissionBlueprint {template_id: $template_id})

        // Optional: Pull the Category for context
        OPTIONAL MATCH (m)-[:BELONGS_TO]->(c:MissionCategory)

        RETURN properties(m) as dna, 
               c.name as category,
               m.version as version,
               m.last_evolved_at as last_modified
        """
        try:
            results = await self._execute_read_query(query, {"template_id": template_id})
            result = results[0]
            dna = result["dna"]
            # Enrich with topological data
            dna["category"] = result.get("category")
            dna["version"] = result.get("version")
            logger.info(f"🧬 [DNA_FETCH] Mission Blueprint loaded: {template_id} (v{dna.get('version')})")
            logger.warning(f"⚠️ [DNA_FETCH] Unauthorized or missing Mission DNA: {template_id}")
            return dna

        except Exception as e:
            logger.error(f"❌ [DNA_FETCH] Critical failure retrieving DNA {template_id}: {e}")
            return None