#!/usr/bin/env python3
"""
XWNode Query Action Executor

This module implements the XWNode query action executor that provides
a unified interface for executing queries across all supported query types
using the existing XWNode strategy system.

Company: eXonware.com
Author: eXonware Backend Team
Email: connect@exonware.com
Version: 0.0.1.8
Generation Date: January 2, 2025
"""

from typing import Any
from datetime import datetime

from .base import AQueryActionExecutor
from .xwquery import XWQueryScriptStrategy
from exonware.xwnode.base import XWNodeBase
from exonware.xwnode.contracts import QueryMode, QueryTrait
from exonware.xwnode.errors import XWNodeValueError
from ..version import __version__


class XWNodeQueryActionExecutor(AQueryActionExecutor):
    """
    XWNode implementation of query action executor.
    
    This executor provides a unified interface for executing queries across
    all 35+ supported query types using the existing XWNode strategy system.
    """
    
    def __init__(self):
        super().__init__()
        self._mode = QueryMode.AUTO
        self._traits = QueryTrait.STRUCTURED | QueryTrait.ANALYTICAL | QueryTrait.BATCH
        
        # All supported query types from XWNode
        self._supported_queries = [
            # Structured & Document Query Languages
            "SQL", "HIVEQL", "PIG", "CQL", "N1QL", "KQL", "DATALOG", 
            "MQL", "PARTIQL",
            
            # Search Query Languages
            "ELASTIC_DSL", "EQL", "LUCENE",
            
            # Time Series & Monitoring
            "FLUX", "PROMQL",
            
            # Data Streaming
            "KSQL",
            
            # Graph Query Languages
            "GRAPHQL", "SPARQL", "GREMLIN", "CYPHER", "GQL",
            
            # ORM / Integrated Query
            "LINQ", "HQL",
            
            # Markup & Document Structure
            "JSONIQ", "JMESPATH", "JQ", "XQUERY", "XPATH",
            
            # Logs & Analytics
            "LOGQL", "SPL",
            
            # SQL Engines
            "TRINO_SQL", "BIGQUERY_SQL", "SNOWFLAKE_SQL",
            
            # Generic Query Languages
            "XML_QUERY", "JSON_QUERY"
        ]
        
        self._strategy_cache = {}
        self._execution_stats = {
            "total_queries": 0,
            "successful_queries": 0,
            "failed_queries": 0,
            "execution_times": []
        }
    
    def execute_query(self, query: str, query_type: str, **kwargs) -> Any:
        """Execute a query using the appropriate XWNode strategy."""
        if not self.validate_query(query, query_type):
            raise XWNodeValueError(f"Invalid {query_type} query: {query}")
        
        start_time = datetime.now()
        self._execution_stats["total_queries"] += 1
        
        try:
            # Get or create strategy instance
            strategy = self._get_strategy(query_type)
            
            # Execute the query
            result = strategy.execute(query, **kwargs)
            
            # Update stats
            execution_time = (datetime.now() - start_time).total_seconds()
            self._execution_stats["successful_queries"] += 1
            self._execution_stats["execution_times"].append(execution_time)
            
            return {
                "result": result,
                "query_type": query_type,
                "execution_time": f"{execution_time:.3f}s",
                "backend": "XWNODE",
                "strategy_used": strategy.__class__.__name__
            }
            
        except Exception as e:
            self._execution_stats["failed_queries"] += 1
            raise XWNodeValueError(f"Query execution failed: {e}")
    
    def validate_query(self, query: str, query_type: str) -> bool:
        """Validate if XWNode can handle this query type."""
        if query_type.upper() not in self._supported_queries:
            return False
        
        try:
            strategy = self._get_strategy(query_type)
            return strategy.validate_query(query)
        except Exception:
            return False
    
    def get_supported_query_types(self) -> list[str]:
        """Get list of query types supported by XWNode."""
        return self._supported_queries.copy()
    
    def _get_strategy(self, query_type: str) -> Any:
        """Get or create strategy instance for query type."""
        query_type_upper = query_type.upper()
        
        if query_type_upper in self._strategy_cache:
            return self._strategy_cache[query_type_upper]
        
        # Import and create strategy instance
        strategy_class = self._get_strategy_class(query_type_upper)
        if not strategy_class:
            raise XWNodeValueError(f"No strategy available for query type: {query_type}")
        
        strategy = strategy_class()
        self._strategy_cache[query_type_upper] = strategy
        return strategy
    
    def _get_strategy_class(self, query_type: str) -> type | None:
        """Get strategy class for query type."""
        strategy_map = {
            "SQL": "sql",
            "HIVEQL": "hiveql",
            "PIG": "pig",
            "CQL": "cql",
            "N1QL": "n1ql",
            "KQL": "kql",
            "DATALOG": "datalog",
            "MQL": "mql",
            "PARTIQL": "partiql",
            "ELASTIC_DSL": "elastic_dsl",
            "EQL": "eql",
            "LUCENE": "lucene",
            "FLUX": "flux",
            "PROMQL": "promql",
            "KSQL": "ksql",
            "GRAPHQL": "graphql",
            "SPARQL": "sparql",
            "GREMLIN": "gremlin",
            "CYPHER": "cypher",
            "GQL": "gql",
            "LINQ": "linq",
            "HQL": "hql",
            "JSONIQ": "jsoniq",
            "JMESPATH": "jmespath",
            "JQ": "jq",
            "XQUERY": "xquery",
            "XPATH": "xpath",
            "LOGQL": "logql",
            "SPL": "spl",
            "TRINO_SQL": "trino_sql",
            "BIGQUERY_SQL": "bigquery_sql",
            "SNOWFLAKE_SQL": "snowflake_sql",
            "XML_QUERY": "xml_query",
            "JSON_QUERY": "json_query"
        }
        
        module_name = strategy_map.get(query_type)
        if not module_name:
            return None
        
        try:
            module = __import__(f'.{module_name}', fromlist=['.'], package=__package__)
            strategy_class_name = f"{query_type.title()}Strategy"
            return getattr(module, strategy_class_name, None)
        except (ImportError, AttributeError):
            return None
    
    def to_native(self) -> XWQueryScriptStrategy:
        """Convert to XWQueryScriptStrategy using actions."""
        return XWQueryScriptStrategy()
    
    def to_actions_tree(self, query: str) -> XWNodeBase:
        """Convert query to actions tree using XWQuery Script."""
        script_strategy = XWQueryScriptStrategy()
        return script_strategy.parse_script(query).get_actions_tree()
    
    def from_actions_tree(self, actions_tree: XWNodeBase) -> str:
        """Convert actions tree to query using XWQuery Script."""
        script_strategy = XWQueryScriptStrategy(actions_tree)
        return script_strategy.to_format("SQL")  # Default to SQL
    
    def get_execution_stats(self) -> dict[str, Any]:
        """Get execution statistics."""
        stats = self._execution_stats.copy()
        
        if stats["execution_times"]:
            stats["avg_execution_time"] = sum(stats["execution_times"]) / len(stats["execution_times"])
            stats["min_execution_time"] = min(stats["execution_times"])
            stats["max_execution_time"] = max(stats["execution_times"])
        else:
            stats["avg_execution_time"] = 0
            stats["min_execution_time"] = 0
            stats["max_execution_time"] = 0
        
        stats["success_rate"] = (
            stats["successful_queries"] / stats["total_queries"] 
            if stats["total_queries"] > 0 else 0
        )
        
        return stats
    
    def clear_cache(self):
        """Clear strategy cache."""
        self._strategy_cache.clear()
    
    def reset_stats(self):
        """Reset execution statistics."""
        self._execution_stats = {
            "total_queries": 0,
            "successful_queries": 0,
            "failed_queries": 0,
            "execution_times": []
        }
    
    def get_backend_info(self) -> dict[str, Any]:
        """Get XWNode backend information."""
        return {
            "backend": "XWNODE",
            "version": __version__,
            "capabilities": [
                "multi_language_queries",
                "format_agnostic",
                "strategy_pattern",
                "enterprise_features",
                "xwquery_script_support"
            ],
            "supported_query_types": len(self._supported_queries),
            "performance_class": "high_performance",
            "execution_stats": self.get_execution_stats()
        }
    
    def estimate_cost(self, query: str, query_type: str) -> dict[str, Any]:
        """Estimate execution cost for XWNode."""
        try:
            strategy = self._get_strategy(query_type)
            plan = strategy.get_query_plan(query)
            
            return {
                "backend": "XWNODE",
                "complexity": plan.get("complexity", "UNKNOWN"),
                "estimated_cost": plan.get("estimated_cost", 0),
                "execution_time": f"{plan.get('estimated_cost', 0)}ms",
                "memory_usage": "low",
                "strategy_used": strategy.__class__.__name__
            }
        except Exception:
            return {
                "backend": "XWNODE",
                "complexity": "UNKNOWN",
                "estimated_cost": 0,
                "execution_time": "0ms",
                "memory_usage": "low",
                "strategy_used": "Unknown"
            }
    
    def execute(self, query: str, context: dict[str, Any] = None, **kwargs) -> Any:
        """Execute query using XWNode strategies."""
        # Determine query type automatically if not specified
        query_type = kwargs.get('query_type', self._detect_query_type(query))
        return self.execute_query(query, query_type, **kwargs)
    
    def get_query_plan(self, query: str) -> dict[str, Any]:
        """Get query execution plan."""
        query_type = self._detect_query_type(query)
        try:
            strategy = self._get_strategy(query_type)
            return strategy.get_query_plan(query)
        except Exception:
            return {
                "query_type": query_type,
                "complexity": "UNKNOWN",
                "estimated_cost": 0,
                "backend": "XWNODE"
            }
    
    def can_handle(self, query_string: str) -> bool:
        """Check if XWNode can handle this query."""
        query_type = self._detect_query_type(query_string)
        return query_type in self._supported_queries
    
    def get_supported_operations(self) -> list[str]:
        """Get list of supported operations."""
        return self._supported_queries.copy()
    
    def estimate_complexity(self, query_string: str) -> dict[str, Any]:
        """Estimate query complexity."""
        query_type = self._detect_query_type(query_string)
        return self.estimate_cost(query_string, query_type)
    
    def _detect_query_type(self, query: str) -> str:
        """Detect query type from query string."""
        query_upper = query.upper()
        
        # Simple detection logic
        if any(keyword in query_upper for keyword in ['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'CREATE', 'DROP']):
            return "SQL"
        elif 'MATCH' in query_upper and ('(' in query or ')' in query):
            return "CYPHER"
        elif 'PREFIX' in query_upper or 'SELECT' in query_upper and 'WHERE' in query_upper:
            return "SPARQL"
        elif query.strip().startswith('{') and 'query' in query_upper:
            return "GRAPHQL"
        elif 'FROM' in query_upper and 'WHERE' in query_upper:
            return "KQL"
        else:
            return "SQL"  # Default fallback
