"""
Query AGS configuration tool for the AGS SPARQL Agent.

This tool queries AGS configuration and metadata including ontologies, data layers, and dashboard configs.
"""

import os
import sys
import asyncio
from datetime import datetime

# Add src directory to path for imports
src_dir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
if src_dir not in sys.path:
    sys.path.insert(0, src_dir)

from ..base_tool import BaseToolMixin, handle_tool_errors, ToolError
from ...utils.agent_utils import get_agent


@handle_tool_errors
async def query_ags_configuration(
    sparql: str = None,
    operation_type: str = "select", 
    explanation: str = None,
    dry_run: bool = False
) -> str:
    """Execute SPARQL queries against AGS transactional RDF triplestore (journal).
    
    This tool enables querying AGS configuration and metadata including ontologies,
    data layers, dashboard configs, and other AGS instance configuration data.
    
    Args:
        sparql: SPARQL query to execute (SELECT/INSERT/UPDATE/DELETE)
        operation_type: Type of operation ("select", "insert", "update", "delete")
        explanation: Human-readable description of the operation
        dry_run: If true, validate query without executing
        
    Returns:
        JSON response with AGS configuration query results or validation info
    """
    BaseToolMixin.validate_required_param(sparql, "sparql")
    
    # Validate operation type
    valid_operations = ["select", "insert", "update", "delete"]
    if operation_type.lower() not in valid_operations:
        raise ToolError(f"Invalid operation_type. Must be one of: {valid_operations}")
    
    # Basic SPARQL syntax validation
    sparql_upper = sparql.upper().strip()
    if operation_type.lower() == "update":
        # Accept SPARQL 1.1 update forms: INSERT, DELETE, WITH
        valid_update_starts = ["INSERT", "DELETE", "WITH"]
        if not any(sparql_upper.startswith(start) for start in valid_update_starts):
            raise ToolError(f"SPARQL update should start with one of {valid_update_starts}")
    else:
        expected_start = operation_type.upper()
        if not sparql_upper.startswith(expected_start):
            raise ToolError(f"SPARQL query should start with {expected_start} for operation_type '{operation_type}'")
    
    # Dry run mode - validate without executing
    if dry_run:
        return BaseToolMixin.create_success_response({
            "dry_run": True,
            "operation_type": operation_type,
            "validated_query": sparql,
            "explanation": explanation or f"Dry run validation for {operation_type} operation"
        }, "Query validated successfully. Set dry_run=false to execute.")
    
    agent = await get_agent()
    
    # Execute against local volume (journal) with 30 second timeout
    start_time = datetime.now()
    timeout_seconds = 30
    
    try:
        result = await asyncio.wait_for(
            asyncio.get_event_loop().run_in_executor(
                None,
                lambda: agent.anzo_client.query_journal(sparql)
            ),
            timeout=timeout_seconds
        )
        execution_time = (datetime.now() - start_time).total_seconds()
        
    except asyncio.TimeoutError:
        execution_time = (datetime.now() - start_time).total_seconds()
        return BaseToolMixin.create_error_response(
            f"Query timed out after {timeout_seconds} seconds",
            details={
                "operation_type": operation_type,
                "execution_time_seconds": execution_time,
                "sparql_query": sparql,
                "timeout_seconds": timeout_seconds
            }
        )
    
    if operation_type.lower() == "select":
        # Handle SELECT query results
        table_results = result.as_table_results().as_list()
        
        return BaseToolMixin.create_success_response({
            "operation_type": operation_type,
            "results": table_results,
            "row_count": len(table_results),
            "execution_time_seconds": execution_time,
            "sparql_query": sparql,
            "explanation": explanation,
            "volume": "local (journal)"
        }, f"Successfully executed {operation_type} query against local volume")
    else:
        # Handle INSERT/UPDATE/DELETE operations
        return BaseToolMixin.create_success_response({
            "operation_type": operation_type,
            "execution_time_seconds": execution_time,
            "sparql_query": sparql,
            "explanation": explanation,
            "volume": "local (journal)"
        }, f"Successfully executed {operation_type} operation against local volume")