"""
GraphQL Query Paradigm - Flexible graph-based queries.
"""

import time
import json
from typing import Dict, Any, List, Optional

from ..base import BaseQueryParadigm, QueryResult


class GraphQLQueryParadigm(BaseQueryParadigm):
    """GraphQL query paradigm for flexible, graph-based data access."""

    @property
    def name(self) -> str:
        return "GraphQL"

    @property
    def description(self) -> str:
        return "Graph-based queries with precise field selection and nested data relationships"

    @property
    def category(self) -> str:
        return "structural"

    @property
    def complexity(self) -> str:
        return "intermediate"

    def execute(self, query: str, config: Dict[str, Any] = None) -> QueryResult:
        """Execute GraphQL query."""
        start_time = time.time()

        try:
            from ...graphql.resolvers import GraphQLResolvers
            from ...graphql.schema import schema

            # Get database path from config
            db_path = config.get('db_path') if config else 'markitect.db'

            # Parse variables if provided
            variables = {}
            if config and 'variables' in config:
                if isinstance(config['variables'], str):
                    variables = json.loads(config['variables'])
                elif isinstance(config['variables'], dict):
                    variables = config['variables']

            # Execute GraphQL query
            result = schema.execute(query, variable_values=variables, context={'db_path': db_path})

            execution_time = (time.time() - start_time) * 1000

            if result.errors:
                return QueryResult(
                    paradigm="GraphQL",
                    query=query,
                    execution_time_ms=execution_time,
                    result_count=0,
                    results=[],
                    metadata={"variables": variables},
                    success=False,
                    error_message=str(result.errors[0])
                )

            # Convert GraphQL result to standard format
            results = []
            result_data = result.data or {}

            # Handle different result types
            for key, value in result_data.items():
                if isinstance(value, list):
                    for item in value:
                        results.append({
                            "query_field": key,
                            **self._flatten_graphql_result(item)
                        })
                elif isinstance(value, dict):
                    results.append({
                        "query_field": key,
                        **self._flatten_graphql_result(value)
                    })
                else:
                    results.append({
                        "query_field": key,
                        "value": value
                    })

            return QueryResult(
                paradigm="GraphQL",
                query=query,
                execution_time_ms=execution_time,
                result_count=len(results),
                results=results,
                metadata={
                    "variables": variables,
                    "query_type": self._detect_query_type(query)
                },
                success=True
            )

        except Exception as e:
            execution_time = (time.time() - start_time) * 1000

            return QueryResult(
                paradigm="GraphQL",
                query=query,
                execution_time_ms=execution_time,
                result_count=0,
                results=[],
                metadata={},
                success=False,
                error_message=str(e)
            )

    def get_examples(self) -> List[Dict[str, str]]:
        """Get example GraphQL queries."""
        return [
            {
                "name": "Basic file query",
                "description": "Get basic information about markdown files",
                "query": """query {
  markdownFiles(limit: 5) {
    id
    filename
    wordCount
    hassFrontMatter
  }
}"""
            },
            {
                "name": "File with front matter",
                "description": "Get files with their front matter data",
                "query": """query {
  markdownFiles(hasFrontMatter: true) {
    filename
    frontMatter {
      key
      value
    }
    createdAt
  }
}"""
            },
            {
                "name": "Schema information",
                "description": "Get schema details and statistics",
                "query": """query {
  schemas {
    filename
    title
    description
    schemaVersion
    propertyCount
  }
}"""
            },
            {
                "name": "Search with variables",
                "description": "Search using variables",
                "query": """query SearchContent($searchTerm: String!) {
  search(query: $searchTerm, limit: 10) {
    type
    score
    file {
      filename
      wordCount
    }
    highlight
  }
}"""
            },
            {
                "name": "Database statistics",
                "description": "Get overall database statistics",
                "query": """query {
  databaseStats {
    totalFiles
    totalSchemas
    totalSizeBytes
    lastUpdated
  }
}"""
            },
            {
                "name": "Specific file by ID",
                "description": "Get detailed information about a specific file",
                "query": """query GetFile($fileId: Int!) {
  markdownFile(id: $fileId) {
    filename
    content
    frontMatterRaw
    wordCount
    lineCount
    createdAt
  }
}"""
            }
        ]

    def validate_query(self, query: str) -> tuple[bool, Optional[str]]:
        """Validate GraphQL query syntax."""
        if not query or not query.strip():
            return False, "Query cannot be empty"

        # Basic GraphQL syntax validation
        query = query.strip()

        # Should start with query, mutation, or subscription
        if not any(query.startswith(keyword) for keyword in ['query', 'mutation', 'subscription', '{']):
            return False, "GraphQL query must start with 'query', 'mutation', 'subscription', or '{'"

        # Check for balanced braces
        open_braces = query.count('{')
        close_braces = query.count('}')
        if open_braces != close_braces:
            return False, "Unmatched braces in GraphQL query"

        # Check for balanced parentheses
        open_parens = query.count('(')
        close_parens = query.count(')')
        if open_parens != close_parens:
            return False, "Unmatched parentheses in GraphQL query"

        return True, None

    def get_syntax_help(self) -> str:
        """Get GraphQL syntax help."""
        return """GraphQL Query Syntax:

Basic Structure:
  query {
    fieldName {
      subfield
    }
  }

Available Root Fields:
  - markdownFile(id: Int, filename: String)
  - markdownFiles(limit: Int, offset: Int, hasFrontMatter: Boolean)
  - schema(id: Int, filename: String)
  - schemas(limit: Int, offset: Int)
  - search(query: String!, type: String, limit: Int)
  - databaseStats
  - astQuery(fileId: Int, filename: String, jsonpath: String!)

Field Selection:
  markdownFiles {
    id
    filename
    wordCount
    frontMatter {
      key
      value
    }
  }

Variables:
  query GetFile($id: Int!) {
    markdownFile(id: $id) {
      filename
      content
    }
  }

Aliases:
  query {
    recent: markdownFiles(limit: 5) { filename }
    old: markdownFiles(offset: 100, limit: 5) { filename }
  }

Fragments:
  fragment FileInfo on MarkdownFile {
    id
    filename
    wordCount
  }

  query {
    markdownFiles {
      ...FileInfo
      createdAt
    }
  }
"""

    def _detect_query_type(self, query: str) -> str:
        """Detect GraphQL query type."""
        query_lower = query.lower().strip()

        if query_lower.startswith('mutation'):
            return "mutation"
        elif query_lower.startswith('subscription'):
            return "subscription"
        elif 'search(' in query_lower:
            return "search_query"
        elif 'astquery(' in query_lower:
            return "ast_query"
        elif any(field in query_lower for field in ['markdownfiles', 'schemas']):
            return "list_query"
        elif any(field in query_lower for field in ['markdownfile', 'schema']):
            return "single_query"
        elif 'databasestats' in query_lower:
            return "stats_query"
        else:
            return "query"

    def _flatten_graphql_result(self, item: Any) -> Dict[str, Any]:
        """Flatten GraphQL result for standardized output."""
        if isinstance(item, dict):
            flattened = {}
            for key, value in item.items():
                if isinstance(value, (dict, list)):
                    flattened[key] = json.dumps(value) if isinstance(value, dict) else value
                else:
                    flattened[key] = value
            return flattened
        else:
            return {"value": item}

    def can_translate_from(self, other_paradigm: str) -> bool:
        """Check if we can translate from another paradigm."""
        return other_paradigm.lower() in ["sql", "natural_language"]

    def translate_query(self, query: str, from_paradigm: str) -> Optional[str]:
        """Translate from another paradigm to GraphQL."""
        if from_paradigm.lower() == "sql":
            return self._translate_sql_to_graphql(query)
        elif from_paradigm.lower() == "natural_language":
            return self._translate_natural_language_to_graphql(query)
        return None

    def _translate_sql_to_graphql(self, query: str) -> Optional[str]:
        """Translate simple SQL to GraphQL."""
        query_upper = query.upper().strip()

        # Simple translations for common patterns
        if 'SELECT * FROM markdown_files' in query_upper:
            return """query {
  markdownFiles {
    id
    filename
    content
    createdAt
  }
}"""
        elif 'SELECT filename FROM markdown_files' in query_upper:
            return """query {
  markdownFiles {
    filename
  }
}"""
        elif 'SELECT * FROM schemas' in query_upper:
            return """query {
  schemas {
    id
    filename
    title
    description
    schemaContent
  }
}"""
        elif 'COUNT(*) FROM markdown_files' in query_upper:
            return """query {
  databaseStats {
    totalFiles
  }
}"""

        return None

    def _translate_natural_language_to_graphql(self, query: str) -> Optional[str]:
        """Translate natural language to GraphQL."""
        query_lower = query.lower()

        if "all files" in query_lower or "list files" in query_lower:
            return """query {
  markdownFiles {
    id
    filename
    wordCount
    createdAt
  }
}"""
        elif "search for" in query_lower:
            # Extract search term
            parts = query_lower.split("search for", 1)
            if len(parts) > 1:
                search_term = parts[1].strip().strip('"\'')
                return f'''query {{
  search(query: "{search_term}") {{
    type
    score
    file {{
      filename
    }}
    highlight
  }}
}}'''
        elif "database statistics" in query_lower or "stats" in query_lower:
            return """query {
  databaseStats {
    totalFiles
    totalSchemas
    totalSizeBytes
    lastUpdated
  }
}"""
        elif "schemas" in query_lower:
            return """query {
  schemas {
    filename
    title
    description
  }
}"""

        return None