"""
Update transformation layer tool for the AGS SPARQL Agent.

Uses REST API (identical in v5.4 and v6.2) instead of journal writes.
"""

import os
import sys

# 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, get_graphmart_uri, get_rest_api_client


@handle_tool_errors
async def update_transformation_layer(
    layer_name_or_uri: str,
    new_title: str = None,
    new_description: str = None,
    new_order_index: int = None,
    new_enabled: bool = None,
    graphmart_uri: str = None,
    explanation: str = None,
    dry_run: bool = False
) -> str:
    """Update properties of an existing transformation layer.
    
    This tool allows updating layer properties without deleting and recreating
    the layer, preserving step order and relationships.
    
    Args:
        layer_name_or_uri: Layer name or full URI to update
        new_title: New title for the layer (optional)
        new_description: New description for the layer (optional)
        new_order_index: New order index for the layer (optional)
        new_enabled: New enabled status for the layer (optional)
        graphmart_uri: URI of the graphmart (optional, auto-detects)
        explanation: Human-readable description of the operation
        dry_run: If true, validate inputs without executing
        
    Returns:
        JSON response with update results
    """
    BaseToolMixin.validate_required_param(layer_name_or_uri, "layer_name_or_uri")
    
    # Validate that at least one update parameter is provided
    update_params = [new_title, new_description, new_order_index, new_enabled]
    if all(param is None for param in update_params):
        raise ToolError("At least one update parameter (new_title, new_description, new_order_index, new_enabled) must be provided")
    
    # Auto-detect graphmart URI if not provided
    graphmart_uri = get_graphmart_uri(graphmart_uri)
    
    agent = await get_agent()
    
    # Resolve layer URI and ordered item URI from name if needed
    layer_uri = None
    layer_ordered_item_uri = None
    current_title = None
    current_description = None
    current_index = None
    current_enabled = None
    
    if layer_name_or_uri.startswith("http://"):
        layer_uri = layer_name_or_uri
        # Find the ordered item for this layer and get current values
        layer_info_query = f"""
        PREFIX gm: <http://cambridgesemantics.com/ontologies/Graphmarts#>
        PREFIX anzo: <http://openanzo.org/ontologies/2008/07/Anzo#>
        PREFIX dc: <http://purl.org/dc/elements/1.1/>
        
        SELECT ?orderedItem ?index ?title ?description ?enabled WHERE {{
            GRAPH <{graphmart_uri}> {{
                <{graphmart_uri}> gm:layer ?orderedItem .
                ?orderedItem anzo:orderedValue <{layer_uri}> ;
                            anzo:index ?index .
                <{layer_uri}> dc:title ?title .
                OPTIONAL {{ <{layer_uri}> dc:description ?description }}
                OPTIONAL {{ <{layer_uri}> gm:enabled ?enabled }}
            }}
        }}
        """
    else:
        # Find layer by name and get current values
        layer_info_query = f"""
        PREFIX gm: <http://cambridgesemantics.com/ontologies/Graphmarts#>
        PREFIX anzo: <http://openanzo.org/ontologies/2008/07/Anzo#>
        PREFIX dc: <http://purl.org/dc/elements/1.1/>
        
        SELECT ?layer ?orderedItem ?index ?description ?enabled WHERE {{
            GRAPH <{graphmart_uri}> {{
                <{graphmart_uri}> gm:layer ?orderedItem .
                ?orderedItem anzo:orderedValue ?layer ;
                            anzo:index ?index .
                ?layer dc:title "{layer_name_or_uri}" .
                OPTIONAL {{ ?layer dc:description ?description }}
                OPTIONAL {{ ?layer gm:enabled ?enabled }}
            }}
        }}
        """
    
    info_result = agent.anzo_client.query_journal(layer_info_query)
    info_table = info_result.as_table_results().as_list()
    
    if not info_table or len(info_table) == 0:
        raise ToolError(f"Layer '{layer_name_or_uri}' not found in graphmart")
    
    if layer_uri is None:
        layer_uri = info_table[0][0]
        layer_ordered_item_uri = info_table[0][1]
        current_index = info_table[0][2]
        current_title = layer_name_or_uri  # We know the title since we searched by it
        current_description = info_table[0][3] if len(info_table[0]) > 3 else None
        current_enabled = info_table[0][4] if len(info_table[0]) > 4 else None
    else:
        layer_ordered_item_uri = info_table[0][0]
        current_index = info_table[0][1]
        current_title = layer_name_or_uri  # We know the title since we searched by it
        current_description = info_table[0][2] if len(info_table[0]) > 2 else None
        current_enabled = info_table[0][3] if len(info_table[0]) > 3 else None
    
    # Check if new_order_index conflicts with existing layers
    if new_order_index is not None and str(new_order_index) != str(current_index):
        # Check for conflicts with other layers
        index_check_query = f"""
        PREFIX anzo: <http://openanzo.org/ontologies/2008/07/Anzo#>
        PREFIX gm: <http://cambridgesemantics.com/ontologies/Graphmarts#>
        PREFIX dc: <http://purl.org/dc/elements/1.1/>
        
        SELECT ?existingLayer ?existingTitle WHERE {{
            GRAPH <{graphmart_uri}> {{
                <{graphmart_uri}> gm:layer ?existingOrderedItem .
                ?existingOrderedItem anzo:orderedValue ?existingLayer ;
                                   anzo:index {new_order_index} .
                ?existingLayer dc:title ?existingTitle .
                FILTER(?existingLayer != <{layer_uri}>)
            }}
        }}
        """
        conflict_result = agent.anzo_client.query_journal(index_check_query)
        conflict_table = conflict_result.as_table_results().as_list()
        
        if conflict_table and len(conflict_table) > 0:
            conflicting_layer = conflict_table[0][1] if len(conflict_table[0]) > 1 else "Unknown"
            raise ToolError(f"Order index {new_order_index} is already used by layer '{conflicting_layer}'. Choose a different index.")
    
    # Build list of changes for reporting
    updates = []
    
    if new_title and new_title != current_title:
        updates.append(f"title: '{current_title}' → '{new_title}'")
    
    if new_description is not None and new_description != current_description:
        updates.append(f"description: '{current_description}' → '{new_description}'")
    
    if new_order_index is not None and str(new_order_index) != str(current_index):
        updates.append(f"order index: {current_index} → {new_order_index}")
    
    if new_enabled is not None and str(new_enabled).lower() != str(current_enabled).lower():
        enabled_value = "true" if new_enabled else "false"
        updates.append(f"enabled: {current_enabled} → {enabled_value}")
    
    if not updates:
        return BaseToolMixin.create_success_response({
            "layer_name_or_uri": layer_name_or_uri,
            "resolved_layer_uri": layer_uri,
            "graphmart_uri": graphmart_uri,
            "changes": "No changes needed"
        }, "No updates required - all values are already current")
    
    # Dry run mode
    if dry_run:
        return BaseToolMixin.create_success_response({
            "dry_run": True,
            "layer_name_or_uri": layer_name_or_uri,
            "resolved_layer_uri": layer_uri,
            "layer_ordered_item_uri": layer_ordered_item_uri,
            "proposed_updates": updates,
            "current_values": {
                "title": current_title,
                "description": current_description,
                "order_index": current_index,
                "enabled": current_enabled
            },
            "new_values": {
                "title": new_title or current_title,
                "description": new_description if new_description is not None else current_description,
                "order_index": new_order_index if new_order_index is not None else current_index,
                "enabled": new_enabled if new_enabled is not None else current_enabled
            },
            "graphmart_uri": graphmart_uri,
            "explanation": explanation
        }, f"Layer update validated. Would make {len(updates)} changes. Set dry_run=false to execute.")
    
    # Execute updates via REST API (single PATCH replaces multi-step DELETE/INSERT)
    api = get_rest_api_client()
    
    # Build kwargs for the PATCH call
    patch_kwargs = {}
    if new_title and new_title != current_title:
        patch_kwargs["title"] = new_title
    if new_description is not None and new_description != current_description:
        patch_kwargs["description"] = new_description
    if new_enabled is not None and str(new_enabled).lower() != str(current_enabled).lower():
        patch_kwargs["enabled"] = new_enabled
    
    if patch_kwargs:
        api.modify_layer(layer_uri, **patch_kwargs)
    
    # For order changes, use move_graphmart_layer
    if new_order_index is not None and str(new_order_index) != str(current_index):
        # Get all layers to find the layer at or near the target position
        layers = api.retrieve_graphmart_layers(graphmart_uri, expand=["title"])
        target_layer_uri = None
        for l in layers:
            if hasattr(l, 'uri') and l.uri != layer_uri:
                # If we find a layer at the target index position, move before it
                target_layer_uri = l.uri
                break
        if target_layer_uri:
            api.move_graphmart_layer(graphmart_uri, layer_uri, before_layer=target_layer_uri)
        updates.append(f"order index: {current_index} → {new_order_index}")
    
    return BaseToolMixin.create_success_response({
        "layer_name_or_uri": layer_name_or_uri,
        "updated_layer_uri": layer_uri,
        "layer_ordered_item_uri": layer_ordered_item_uri,
        "applied_updates": updates,
        "updated_values": {
            "title": new_title or current_title,
            "description": new_description if new_description is not None else current_description,
            "order_index": new_order_index if new_order_index is not None else current_index,
            "enabled": new_enabled if new_enabled is not None else current_enabled
        },
        "graphmart_uri": graphmart_uri,
        "explanation": explanation
    }, f"Successfully updated transformation layer '{layer_name_or_uri}' with {len(updates)} changes")