"""
MCP Extensions for Context Awareness
Implements the Factory Pattern to wrap existing tools with context
and defines 5 new tools for the Context Compiler.
"""

from typing import Any, Dict, List, Callable
import functools
import json
import os
from .compiler import ContextCompiler

# Singleton compiler instance
COMPILER = ContextCompiler(skins_dir=os.path.join(os.path.dirname(__file__), "skins"))

# --- FACTORY PATTERN: Context Wrapper ---

def with_context(default_manifest_path: str = None):
    """
    Decorator that injects the compiled context into the tool's arguments.
    Use this to upgrade existing 'token extractor' tools to be 'context aware'.

    The manifest path is extracted from kwargs['manifest_path'] if present,
    otherwise falls back to the default_manifest_path provided at decoration time.
    """
    def decorator(func: Callable):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 1. Get manifest path (runtime kwarg or decorator default)
            manifest_path = kwargs.get('manifest_path', default_manifest_path)
            if not manifest_path:
                raise ValueError("No manifest_path provided to context-aware tool")

            # 2. Compile Context
            context = COMPILER.compile(manifest_path)

            # 3. Inject into kwargs
            kwargs['dss_context'] = context

            # 4. Execute Tool
            return func(*args, **kwargs)
        return wrapper
    return decorator


# --- 5 NEW MCP TOOLS ---

def get_active_context(manifest_path: str, debug: bool = False, force_refresh: bool = False) -> str:
    """
    [Tool 1] Returns the fully resolved JSON context for the project.
    Set debug=True to see provenance (which layer defined which token).
    Set force_refresh=True to bypass cache (for long-running servers).
    """
    context = COMPILER.compile(manifest_path, debug=debug, force_refresh=force_refresh)
    return json.dumps(context, indent=2)

def resolve_token(manifest_path: str, token_path: str, force_refresh: bool = False) -> str:
    """
    [Tool 2] Resolves a specific token value (e.g. 'colors.primary')
    through the cascade.
    Set force_refresh=True to bypass cache (for long-running servers).
    """
    context = COMPILER.compile(manifest_path, force_refresh=force_refresh)
    keys = token_path.split('.')
    current = context.get("tokens", {})

    for k in keys:
        if isinstance(current, dict) and k in current:
            current = current[k]
        else:
            return f"Token not found: {token_path}"

    return str(current)

def validate_manifest(manifest_path: str) -> str:
    """
    [Tool 3] Validates the ds.config.json against the schema.
    """
    # In a full implementation, we would use 'jsonschema' library here.
    # For now, we perform a basic structural check via the Compiler's loader.
    try:
        COMPILER.compile(manifest_path)
        return "Valid: Project manifest builds successfully."
    except Exception as e:
        return f"Invalid: {str(e)}"

def list_skins() -> str:
    """
    [Tool 4] Lists all available skins in the registry.
    """
    skins_path = COMPILER.skins_dir
    if not skins_path.exists():
        return "No skins directory found."

    skins = [f.stem for f in skins_path.glob("*.json")]
    return json.dumps(skins)

def get_compiler_status() -> str:
    """
    [Tool 5] Returns the health and configuration of the Context Compiler.
    """
    status = {
        "status": "active",
        "skins_directory": str(COMPILER.skins_dir),
        "cached_skins": list(COMPILER.cache.keys()),
        "safe_boot_ready": True
    }
    return json.dumps(status, indent=2)

# Instructions for Main Server File:
# 1. Import these tools
# 2. Register them with the MCP server instance
# 3. Apply @with_context wrapper to legacy tools if dynamic context is needed
