"""
Unified MCP tools for Unified Agent (Phase 3D-3 consolidation).

Consolidates 10 individual unified agent tools into 3 action-dispatched tools:
- book_sync(action, ...) — 4 actions: checkout, promote, sync, diff
- book_research(analysis_type, ...) — 3 types: analyze, compare_to_db, profile_sources
- unified_workflow(action, ...) — 3 actions: create, execute, get_context

Original tool names are preserved as deprecation wrappers in mcp_tools.py.
Pattern: mcp_only (no settings parameter).
"""

import logging
from collections import defaultdict
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional

logger = logging.getLogger(__name__)


# ============================================================================
# book_sync action handlers
# ============================================================================

def _sync_checkout(**kwargs) -> Dict[str, Any]:
    from .context import get_context
    from .bridges.librarian_bridge import LibrarianBridge

    project_id = kwargs.get("project_id")
    if not project_id:
        return {"error": "project_id is required for 'checkout' action"}

    ctx = get_context()
    config = ctx.librarian_config

    bridge = LibrarianBridge(
        base_url=config["base_url"],
        api_key=config["api_key"],
    )

    book_name = kwargs.get("book_name")
    book, result = bridge.checkout_librarian_to_book(project_id, book_name)

    if book:
        ctx.register_book(book, source_project_id=project_id)
        ctx.active_project_id = project_id

        ctx.record_operation(
            operation="checkout",
            source_system="librarian",
            target_system="book",
            details={
                "project_id": project_id,
                "book_name": book.name,
                "hierarchy_count": result["hierarchy_count"],
            },
        )

        return {
            "success": True,
            "book_name": book.name,
            "hierarchy_count": result["hierarchy_count"],
            "root_node_count": len(book.root_nodes),
            "message": f"Successfully checked out project '{project_id}' to Book '{book.name}'",
        }
    else:
        ctx.record_operation(
            operation="checkout",
            source_system="librarian",
            target_system="book",
            details={"project_id": project_id},
            success=False,
            error_message="; ".join(result.get("errors", [])),
        )

        return {
            "success": False,
            "errors": result.get("errors", ["Unknown error"]),
        }


def _sync_promote(**kwargs) -> Dict[str, Any]:
    from .context import get_context
    from .bridges.librarian_bridge import LibrarianBridge

    book_name = kwargs.get("book_name")
    if not book_name:
        return {"error": "book_name is required for 'promote' action"}

    ctx = get_context()

    book = ctx.get_book(book_name)
    if not book:
        return {
            "success": False,
            "error": f"Book '{book_name}' not found in context. Use list_books() to see available books.",
        }

    config = ctx.librarian_config
    bridge = LibrarianBridge(
        base_url=config["base_url"],
        api_key=config["api_key"],
    )

    result = bridge.promote_book_to_librarian(
        book=book,
        project_name=kwargs.get("project_name") or book.name,
        project_description=kwargs.get("project_description", ""),
        existing_project_id=kwargs.get("existing_project_id"),
    )

    ctx.record_operation(
        operation="promote",
        source_system="book",
        target_system="librarian",
        details={
            "book_name": book_name,
            "project_id": result.get("project_id"),
            "created": result.get("created_hierarchies", 0),
            "updated": result.get("updated_hierarchies", 0),
        },
        success=result.get("success", False),
        error_message="; ".join(result.get("errors", [])) if result.get("errors") else None,
    )

    if result.get("success"):
        ctx.active_project_id = result.get("project_id")

        return {
            "success": True,
            "project_id": result.get("project_id"),
            "created_hierarchies": result.get("created_hierarchies", 0),
            "updated_hierarchies": result.get("updated_hierarchies", 0),
            "message": f"Successfully promoted Book '{book_name}' to Librarian project",
        }
    else:
        return {
            "success": False,
            "errors": result.get("errors", ["Unknown error"]),
            "project_id": result.get("project_id"),
        }


def _sync_sync(**kwargs) -> Dict[str, Any]:
    from .context import get_context
    from .bridges.librarian_bridge import LibrarianBridge

    book_name = kwargs.get("book_name")
    project_id = kwargs.get("project_id")
    if not book_name or not project_id:
        return {"error": "book_name and project_id are required for 'sync' action"}

    ctx = get_context()

    book = ctx.get_book(book_name)
    if not book:
        return {
            "success": False,
            "error": f"Book '{book_name}' not found in context",
        }

    config = ctx.librarian_config
    bridge = LibrarianBridge(
        base_url=config["base_url"],
        api_key=config["api_key"],
    )

    result = bridge.sync_book_and_librarian(
        book=book,
        project_id=project_id,
        direction=kwargs.get("direction", "bidirectional"),
        conflict_resolution=kwargs.get("conflict_resolution", "book_wins"),
    )

    ctx.record_operation(
        operation="sync",
        source_system="book",
        target_system="librarian",
        details={
            "book_name": book_name,
            "project_id": project_id,
            "direction": kwargs.get("direction", "bidirectional"),
            "pushed": result.get("pushed", 0),
            "pulled": result.get("pulled", 0),
        },
        success=result.get("success", False),
    )

    return result


def _sync_diff(**kwargs) -> Dict[str, Any]:
    from .context import get_context
    from .bridges.librarian_bridge import LibrarianBridge

    book_name = kwargs.get("book_name")
    project_id = kwargs.get("project_id")
    if not book_name or not project_id:
        return {"error": "book_name and project_id are required for 'diff' action"}

    ctx = get_context()

    book = ctx.get_book(book_name)
    if not book:
        return {
            "success": False,
            "error": f"Book '{book_name}' not found in context",
        }

    config = ctx.librarian_config
    bridge = LibrarianBridge(
        base_url=config["base_url"],
        api_key=config["api_key"],
    )

    diff = bridge.diff_book_project(book, project_id)

    return {
        "success": True,
        "book_name": book_name,
        "project_id": project_id,
        **diff.to_dict(),
    }


# ============================================================================
# book_research type handlers
# ============================================================================

def _research_analyze(**kwargs) -> Dict[str, Any]:
    from .context import get_context
    from .bridges.researcher_bridge import ResearcherBridge

    book_name = kwargs.get("book_name")
    connection_id = kwargs.get("connection_id")
    if not book_name or not connection_id:
        return {"error": "book_name and connection_id are required for 'analyze' type"}

    ctx = get_context()

    book = ctx.get_book(book_name)
    if not book:
        return {
            "success": False,
            "error": f"Book '{book_name}' not found in context",
        }

    config = ctx.researcher_config
    bridge = ResearcherBridge(
        base_url=config["base_url"],
        api_key=config["api_key"],
    )

    result = bridge.analyze_book(
        book=book,
        connection_id=connection_id,
        analysis_type=kwargs.get("analysis_type", "validate_sources"),
    )

    ctx.record_operation(
        operation="analyze",
        source_system="book",
        target_system="researcher",
        details={
            "book_name": book_name,
            "connection_id": connection_id,
            "analysis_type": kwargs.get("analysis_type", "validate_sources"),
        },
    )

    return {
        "success": True,
        **result,
    }


def _research_compare_to_db(**kwargs) -> Dict[str, Any]:
    from .context import get_context
    from .bridges.researcher_bridge import ResearcherBridge

    book_name = kwargs.get("book_name")
    connection_id = kwargs.get("connection_id")
    if not book_name or not connection_id:
        return {"error": "book_name and connection_id are required for 'compare_to_db' type"}

    ctx = get_context()

    book = ctx.get_book(book_name)
    if not book:
        return {
            "success": False,
            "error": f"Book '{book_name}' not found in context",
        }

    config = ctx.researcher_config
    bridge = ResearcherBridge(
        base_url=config["base_url"],
        api_key=config["api_key"],
    )

    sources = bridge.extract_sources_from_book(book)

    hierarchy_filter = kwargs.get("hierarchy_filter")
    if hierarchy_filter:
        sources = [s for s in sources if s.hierarchy_id == hierarchy_filter]

    if not sources:
        return {
            "success": True,
            "message": "No source mappings found to compare",
            "comparisons": [],
        }

    comparisons = []
    hier_sources = defaultdict(list)
    for s in sources:
        hier_sources[s.hierarchy_id].append(s)

    for hier_id, hier_sources_list in hier_sources.items():
        for source in hier_sources_list:
            comparison = bridge.compare_hierarchy_data(
                hierarchy_id=hier_id,
                connection_id=connection_id,
                hierarchy_values=[source.uid] if source.uid else [],
                source_mapping=source,
            )
            comparisons.append(comparison.to_dict())

    ctx.record_operation(
        operation="compare_data",
        source_system="book",
        target_system="researcher",
        details={
            "book_name": book_name,
            "connection_id": connection_id,
            "comparisons": len(comparisons),
        },
    )

    return {
        "success": True,
        "book_name": book_name,
        "comparisons": comparisons,
        "summary": {
            "total_comparisons": len(comparisons),
            "total_matches": sum(c.get("matches", 0) for c in comparisons),
            "total_orphans_in_hierarchy": sum(c.get("orphans_in_hierarchy", 0) for c in comparisons),
            "total_orphans_in_database": sum(c.get("orphans_in_database", 0) for c in comparisons),
        },
    }


def _research_profile_sources(**kwargs) -> Dict[str, Any]:
    from .context import get_context
    from .bridges.researcher_bridge import ResearcherBridge

    book_name = kwargs.get("book_name")
    connection_id = kwargs.get("connection_id")
    if not book_name or not connection_id:
        return {"error": "book_name and connection_id are required for 'profile_sources' type"}

    ctx = get_context()

    book = ctx.get_book(book_name)
    if not book:
        return {
            "success": False,
            "error": f"Book '{book_name}' not found in context",
        }

    config = ctx.researcher_config
    bridge = ResearcherBridge(
        base_url=config["base_url"],
        api_key=config["api_key"],
    )

    sources = bridge.extract_sources_from_book(book)
    result = bridge.profile_sources(sources, connection_id)

    ctx.record_operation(
        operation="profile_sources",
        source_system="book",
        target_system="researcher",
        details={
            "book_name": book_name,
            "connection_id": connection_id,
            "source_count": len(sources),
        },
    )

    return {
        "success": True,
        "book_name": book_name,
        **result,
    }


# ============================================================================
# unified_workflow action handlers
# ============================================================================

def _workflow_create(**kwargs) -> Dict[str, Any]:
    from .context import get_context

    workflow_name = kwargs.get("workflow_name")
    description = kwargs.get("description")
    steps = kwargs.get("steps")
    if not workflow_name or not description or not steps:
        return {"error": "workflow_name, description, and steps are required for 'create' action"}

    ctx = get_context()

    valid_systems = {"book", "librarian", "researcher"}
    for i, step in enumerate(steps):
        if step.get("system") not in valid_systems:
            return {
                "success": False,
                "error": f"Step {i}: Invalid system '{step.get('system')}'. Must be one of: {valid_systems}",
            }
        if not step.get("action"):
            return {
                "success": False,
                "error": f"Step {i}: Missing 'action' field",
            }

    workflow = {
        "name": workflow_name,
        "description": description,
        "steps": steps,
        "created_at": datetime.now(timezone.utc).isoformat(),
        "status": "created",
    }

    if not hasattr(ctx, '_workflows'):
        ctx._workflows = {}
    ctx._workflows[workflow_name] = workflow

    ctx.record_operation(
        operation="create_workflow",
        source_system="unified",
        target_system=None,
        details={
            "workflow_name": workflow_name,
            "step_count": len(steps),
        },
    )

    return {
        "success": True,
        "workflow": workflow,
        "message": f"Created workflow '{workflow_name}' with {len(steps)} steps",
    }


def _workflow_execute(mcp=None, **kwargs) -> Dict[str, Any]:
    from .context import get_context

    workflow_name = kwargs.get("workflow_name")
    if not workflow_name:
        return {"error": "workflow_name is required for 'execute' action"}

    ctx = get_context()

    if not hasattr(ctx, '_workflows') or workflow_name not in ctx._workflows:
        return {
            "success": False,
            "error": f"Workflow '{workflow_name}' not found. Create it first with unified_workflow(action='create', ...).",
        }

    workflow = ctx._workflows[workflow_name]
    results = []
    context_params = kwargs.get("context_params") or {}

    for i, step in enumerate(workflow["steps"]):
        step_result = {
            "step": i,
            "system": step["system"],
            "action": step["action"],
        }

        try:
            if step["system"] == "book":
                step_result["result"] = {"message": "Book action would execute here"}
                step_result["status"] = "simulated"

            elif step["system"] == "librarian":
                if step["action"] == "promote" and mcp:
                    if "book_name" in context_params:
                        tool_fn = mcp._tool_manager._tools.get("promote_book_to_librarian")
                        if tool_fn:
                            result = tool_fn.fn(
                                book_name=context_params["book_name"],
                                **step.get("params", {}),
                            )
                            step_result["result"] = result
                            step_result["status"] = "completed" if result.get("success") else "failed"
                        else:
                            step_result["result"] = {"error": "Tool not found"}
                            step_result["status"] = "failed"
                    else:
                        step_result["result"] = {"error": "book_name not in context"}
                        step_result["status"] = "failed"
                else:
                    step_result["result"] = {"message": "Librarian action would execute here"}
                    step_result["status"] = "simulated"

            elif step["system"] == "researcher":
                if step["action"] == "validate_sources" and mcp:
                    if "book_name" in context_params and "connection_id" in context_params:
                        tool_fn = mcp._tool_manager._tools.get("analyze_book_with_researcher")
                        if tool_fn:
                            result = tool_fn.fn(
                                book_name=context_params["book_name"],
                                connection_id=context_params["connection_id"],
                                analysis_type="validate_sources",
                            )
                            step_result["result"] = result
                            step_result["status"] = "completed" if result.get("success") else "failed"
                        else:
                            step_result["result"] = {"error": "Tool not found"}
                            step_result["status"] = "failed"
                    else:
                        step_result["result"] = {"error": "book_name or connection_id not in context"}
                        step_result["status"] = "failed"
                else:
                    step_result["result"] = {"message": "Researcher action would execute here"}
                    step_result["status"] = "simulated"

        except Exception as e:
            step_result["status"] = "error"
            step_result["error"] = str(e)

        results.append(step_result)

        if step_result.get("status") == "failed" and not step.get("continue_on_error"):
            break

    ctx.record_operation(
        operation="execute_workflow",
        source_system="unified",
        target_system=None,
        details={
            "workflow_name": workflow_name,
            "steps_executed": len(results),
            "success_count": sum(1 for r in results if r.get("status") == "completed"),
        },
    )

    return {
        "success": all(r.get("status") in ("completed", "simulated") for r in results),
        "workflow_name": workflow_name,
        "results": results,
        "summary": {
            "total_steps": len(workflow["steps"]),
            "executed": len(results),
            "completed": sum(1 for r in results if r.get("status") == "completed"),
            "simulated": sum(1 for r in results if r.get("status") == "simulated"),
            "failed": sum(1 for r in results if r.get("status") == "failed"),
        },
    }


def _workflow_get_context(**kwargs) -> Dict[str, Any]:
    from .context import get_context

    ctx = get_context()

    summary = ctx.get_context_summary()

    if hasattr(ctx, '_workflows'):
        summary["workflows"] = list(ctx._workflows.keys())

    return {
        "success": True,
        **summary,
    }


# ============================================================================
# Action dispatch dictionaries
# ============================================================================

_SYNC_ACTIONS = {
    "checkout": _sync_checkout,
    "promote": _sync_promote,
    "sync": _sync_sync,
    "diff": _sync_diff,
}

_RESEARCH_TYPES = {
    "analyze": _research_analyze,
    "compare_to_db": _research_compare_to_db,
    "profile_sources": _research_profile_sources,
}

_WORKFLOW_ACTIONS = {
    "create": _workflow_create,
    "execute": _workflow_execute,
    "get_context": _workflow_get_context,
}


# ============================================================================
# Unified dispatch functions
# ============================================================================

def dispatch_book_sync(action: str, **kwargs) -> Dict[str, Any]:
    """Dispatch a book_sync action."""
    handler = _SYNC_ACTIONS.get(action)
    if not handler:
        return {
            "error": f"Unknown action: '{action}'",
            "valid_actions": sorted(_SYNC_ACTIONS.keys()),
        }
    try:
        return handler(**kwargs)
    except Exception as e:
        logger.error(f"book_sync({action}) failed: {e}")
        return {"error": f"book_sync({action}) failed: {e}"}


def dispatch_book_research(analysis_type: str, **kwargs) -> Dict[str, Any]:
    """Dispatch a book_research analysis type."""
    handler = _RESEARCH_TYPES.get(analysis_type)
    if not handler:
        return {
            "error": f"Unknown analysis_type: '{analysis_type}'",
            "valid_types": sorted(_RESEARCH_TYPES.keys()),
        }
    try:
        return handler(**kwargs)
    except Exception as e:
        logger.error(f"book_research({analysis_type}) failed: {e}")
        return {"error": f"book_research({analysis_type}) failed: {e}"}


def dispatch_unified_workflow(action: str, mcp=None, **kwargs) -> Dict[str, Any]:
    """Dispatch a unified_workflow action."""
    handler = _WORKFLOW_ACTIONS.get(action)
    if not handler:
        return {
            "error": f"Unknown action: '{action}'",
            "valid_actions": sorted(_WORKFLOW_ACTIONS.keys()),
        }
    try:
        # execute handler needs mcp reference for tool dispatch
        if action == "execute":
            return handler(mcp=mcp, **kwargs)
        return handler(**kwargs)
    except Exception as e:
        logger.error(f"unified_workflow({action}) failed: {e}")
        return {"error": f"unified_workflow({action}) failed: {e}"}


# ============================================================================
# Registration
# ============================================================================

def register_unified_agent_unified_tools(mcp):
    """Register the 3 unified agent MCP tools."""

    @mcp.tool()
    def book_sync(
        action: str,
        project_id: Optional[str] = None,
        book_name: Optional[str] = None,
        project_name: Optional[str] = None,
        project_description: str = "",
        existing_project_id: Optional[str] = None,
        direction: str = "bidirectional",
        conflict_resolution: str = "book_wins",
    ) -> Dict[str, Any]:
        """
        Unified Book-Librarian sync tool. Replaces 4 individual tools.

        Actions:
        - checkout: Convert Librarian project to Book (requires project_id)
        - promote: Create/update Librarian project from Book (requires book_name)
        - sync: Bidirectional sync between Book and Librarian (requires book_name, project_id)
        - diff: Show differences between Book and Librarian (requires book_name, project_id)

        Args:
            action: The action to perform (checkout, promote, sync, diff)
            project_id: Librarian project ID (for checkout, sync, diff)
            book_name: Name of the registered Book (for promote, sync, diff; optional for checkout)
            project_name: Name for the Librarian project (for promote)
            project_description: Description for the project (for promote)
            existing_project_id: Update existing project instead of creating new (for promote)
            direction: Sync direction - to_librarian, from_librarian, or bidirectional (for sync)
            conflict_resolution: How to resolve conflicts - book_wins or librarian_wins (for sync)

        Returns:
            Action-specific result dict
        """
        return dispatch_book_sync(action, **{
            k: v for k, v in {
                "project_id": project_id, "book_name": book_name,
                "project_name": project_name, "project_description": project_description,
                "existing_project_id": existing_project_id,
                "direction": direction, "conflict_resolution": conflict_resolution,
            }.items() if v is not None
        })

    @mcp.tool()
    def book_research(
        analysis_type: str,
        book_name: Optional[str] = None,
        connection_id: Optional[str] = None,
        hierarchy_filter: Optional[str] = None,
    ) -> Dict[str, Any]:
        """
        Unified Book research and analytics tool. Replaces 3 individual tools.

        Types:
        - analyze: Validate Book sources against database (requires book_name, connection_id)
        - compare_to_db: Compare hierarchy values with live data (requires book_name, connection_id)
        - profile_sources: Profile data for all source mappings (requires book_name, connection_id)

        Args:
            analysis_type: The analysis type (analyze, compare_to_db, profile_sources)
            book_name: Name of the registered Book
            connection_id: Database connection ID for validation
            hierarchy_filter: Optional hierarchy ID filter (for compare_to_db)

        Returns:
            Analysis-type-specific result dict
        """
        return dispatch_book_research(analysis_type, **{
            k: v for k, v in {
                "book_name": book_name, "connection_id": connection_id,
                "hierarchy_filter": hierarchy_filter,
            }.items() if v is not None
        })

    @mcp.tool()
    def unified_workflow(
        action: str,
        workflow_name: Optional[str] = None,
        description: Optional[str] = None,
        steps: Optional[List[Dict[str, Any]]] = None,
        context_params: Optional[Dict[str, Any]] = None,
    ) -> Dict[str, Any]:
        """
        Unified workflow management tool. Replaces 3 individual tools.

        Actions:
        - create: Create a workflow plan (requires workflow_name, description, steps)
        - execute: Execute a previously created workflow (requires workflow_name)
        - get_context: Get current context across all systems (no required params)

        Args:
            action: The action to perform (create, execute, get_context)
            workflow_name: Name of the workflow (for create, execute)
            description: Description of the workflow (for create)
            steps: List of workflow steps with system, action, params (for create)
            context_params: Parameters to pass to workflow execution (for execute)

        Returns:
            Action-specific result dict
        """
        return dispatch_unified_workflow(action, mcp=mcp, **{
            k: v for k, v in {
                "workflow_name": workflow_name, "description": description,
                "steps": steps, "context_params": context_params,
            }.items() if v is not None
        })

    logger.info("Registered 3 unified agent tools: book_sync, book_research, unified_workflow")
    return ["book_sync", "book_research", "unified_workflow"]
