"""
DSS Debug Tools for MCP

This module implements the MCP tool layer that bridges Claude Code to the DSS Debug API.
It allows the LLM to inspect browser sessions, check server health, and run debug workflows.

Configuration:
    DSS_DEBUG_API_URL: Base URL for the DSS Debug API (default: http://localhost:3456)
"""

import os
import json
import logging
from pathlib import Path
from typing import Dict, Any, List, Optional
from datetime import datetime
from mcp import types

try:
    import httpx
except ImportError:
    httpx = None


# Configure logging
logger = logging.getLogger(__name__)

# Configuration
DSS_API_URL = os.getenv("DSS_DEBUG_API_URL", "http://localhost:3456")
DEFAULT_LOG_LIMIT = 50

# Tool definitions (metadata for Claude)
DEBUG_TOOLS = [
    types.Tool(
        name="dss_list_browser_sessions",
        description="List all browser log sessions that have been captured. Use this to find session IDs for detailed analysis.",
        inputSchema={
            "type": "object",
            "properties": {},
            "required": []
        }
    ),
    types.Tool(
        name="dss_get_browser_diagnostic",
        description="Get diagnostic summary for a specific browser session including log counts, error counts, and session metadata",
        inputSchema={
            "type": "object",
            "properties": {
                "session_id": {
                    "type": "string",
                    "description": "Session ID to inspect. If omitted, uses the most recent session."
                }
            },
            "required": []
        }
    ),
    types.Tool(
        name="dss_get_browser_errors",
        description="Get console errors and exceptions from a browser session. Filters logs to show only errors and warnings.",
        inputSchema={
            "type": "object",
            "properties": {
                "session_id": {
                    "type": "string",
                    "description": "Session ID. Defaults to most recent if omitted."
                },
                "limit": {
                    "type": "integer",
                    "description": "Maximum number of errors to retrieve (default: 50)",
                    "default": 50
                }
            },
            "required": []
        }
    ),
    types.Tool(
        name="dss_get_browser_network",
        description="Get network request logs from a browser session. Useful for checking failed API calls (404, 500) or latency issues.",
        inputSchema={
            "type": "object",
            "properties": {
                "session_id": {
                    "type": "string",
                    "description": "Session ID. Defaults to most recent if omitted."
                },
                "limit": {
                    "type": "integer",
                    "description": "Maximum number of entries to retrieve (default: 50)",
                    "default": 50
                }
            },
            "required": []
        }
    ),
    types.Tool(
        name="dss_get_server_status",
        description="Quick check if the DSS Debug Server is up and running. Returns simple UP/DOWN status from health check.",
        inputSchema={
            "type": "object",
            "properties": {},
            "required": []
        }
    ),
    types.Tool(
        name="dss_get_server_diagnostic",
        description="Get detailed server health diagnostics including memory usage, database size, process info, and recent errors. Use for deep debugging of infrastructure.",
        inputSchema={
            "type": "object",
            "properties": {},
            "required": []
        }
    ),
    types.Tool(
        name="dss_list_workflows",
        description="List available debug workflows that can be executed. Workflows are predefined diagnostic procedures.",
        inputSchema={
            "type": "object",
            "properties": {},
            "required": []
        }
    ),
    types.Tool(
        name="dss_run_workflow",
        description="Execute a predefined debug workflow by ID. Workflows contain step-by-step diagnostic procedures.",
        inputSchema={
            "type": "object",
            "properties": {
                "workflow_id": {
                    "type": "string",
                    "description": "The ID of the workflow to run (see dss_list_workflows for available IDs)"
                }
            },
            "required": ["workflow_id"]
        }
    )
]


class DebugTools:
    """Debug tool implementations"""

    def __init__(self):
        self.api_base = DSS_API_URL
        self.browser_logs_dir = None

    def _get_browser_logs_dir(self) -> Path:
        """Get the browser logs directory path"""
        if self.browser_logs_dir is None:
            # Assuming we're in tools/dss_mcp/tools/debug_tools.py
            # Root is 3 levels up
            root = Path(__file__).parent.parent.parent.parent
            self.browser_logs_dir = root / ".dss" / "browser-logs"
        return self.browser_logs_dir

    async def _request(
        self,
        method: str,
        endpoint: str,
        params: Optional[Dict[str, Any]] = None,
        json_data: Optional[Dict[str, Any]] = None
    ) -> Dict[str, Any]:
        """
        Internal helper to make safe HTTP requests to the DSS Debug API.
        """
        if httpx is None:
            return {"error": "httpx library not installed. Run: pip install httpx"}

        url = f"{self.api_base.rstrip('/')}/{endpoint.lstrip('/')}"

        async with httpx.AsyncClient(timeout=10.0) as client:
            try:
                response = await client.request(method, url, params=params, json=json_data)

                # Handle non-200 responses
                if response.status_code >= 400:
                    try:
                        error_detail = response.json().get("detail", response.text)
                    except Exception:
                        error_detail = response.text
                    return {
                        "error": f"API returned status {response.status_code}",
                        "detail": error_detail
                    }

                # Return JSON if possible
                try:
                    return response.json()
                except Exception:
                    return {"result": response.text}

            except httpx.ConnectError:
                return {
                    "error": f"Could not connect to DSS Debug API at {self.api_base}",
                    "suggestion": "Please ensure the debug server is running (cd tools/api && python3 -m uvicorn server:app --port 3456)"
                }
            except httpx.TimeoutException:
                return {"error": f"Request to DSS Debug API timed out ({url})"}
            except Exception as e:
                logger.error(f"DSS API Request failed: {e}")
                return {"error": f"Unexpected error: {str(e)}"}

    def _get_latest_session_id(self) -> Optional[str]:
        """Get the most recent browser session ID from filesystem"""
        logs_dir = self._get_browser_logs_dir()

        if not logs_dir.exists():
            return None

        # Get all .json files
        json_files = list(logs_dir.glob("*.json"))

        if not json_files:
            return None

        # Sort by modification time, most recent first
        json_files.sort(key=lambda p: p.stat().st_mtime, reverse=True)

        # Return filename without .json extension
        return json_files[0].stem

    async def execute_tool(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
        """Execute a tool by name"""
        handlers = {
            "dss_list_browser_sessions": self.list_browser_sessions,
            "dss_get_browser_diagnostic": self.get_browser_diagnostic,
            "dss_get_browser_errors": self.get_browser_errors,
            "dss_get_browser_network": self.get_browser_network,
            "dss_get_server_status": self.get_server_status,
            "dss_get_server_diagnostic": self.get_server_diagnostic,
            "dss_list_workflows": self.list_workflows,
            "dss_run_workflow": self.run_workflow
        }

        handler = handlers.get(tool_name)
        if not handler:
            return {"error": f"Unknown tool: {tool_name}"}

        try:
            result = await handler(**arguments)
            return result
        except Exception as e:
            logger.error(f"Tool execution failed: {e}")
            return {"error": str(e)}

    async def list_browser_sessions(self) -> Dict[str, Any]:
        """List all browser log sessions"""
        logs_dir = self._get_browser_logs_dir()

        if not logs_dir.exists():
            return {
                "sessions": [],
                "count": 0,
                "message": "No browser logs directory found. Browser logger may not have captured any sessions yet."
            }

        # Get all .json files
        json_files = list(logs_dir.glob("*.json"))

        if not json_files:
            return {
                "sessions": [],
                "count": 0,
                "message": "No sessions found in browser logs directory."
            }

        # Sort by modification time, most recent first
        json_files.sort(key=lambda p: p.stat().st_mtime, reverse=True)

        sessions = []
        for json_file in json_files:
            try:
                # Read session metadata
                with open(json_file, 'r') as f:
                    data = json.load(f)

                sessions.append({
                    "session_id": json_file.stem,
                    "exported_at": data.get("exportedAt", "unknown"),
                    "log_count": len(data.get("logs", [])),
                    "file_size_bytes": json_file.stat().st_size,
                    "modified_at": datetime.fromtimestamp(json_file.stat().st_mtime).isoformat()
                })
            except Exception as e:
                logger.warning(f"Could not read session file {json_file}: {e}")
                sessions.append({
                    "session_id": json_file.stem,
                    "error": f"Could not parse: {str(e)}"
                })

        return {
            "sessions": sessions,
            "count": len(sessions),
            "directory": str(logs_dir)
        }

    async def get_browser_diagnostic(self, session_id: Optional[str] = None) -> Dict[str, Any]:
        """Get diagnostic summary for a browser session"""
        # Resolve session_id
        if not session_id:
            session_id = self._get_latest_session_id()
            if not session_id:
                return {"error": "No active session found"}

        # Fetch session data from API
        response = await self._request("GET", f"/api/browser-logs/{session_id}")

        if "error" in response:
            return response

        # Extract diagnostic info
        logs = response.get("logs", [])
        diagnostic = response.get("diagnostic", {})

        # Calculate additional metrics
        error_count = sum(1 for log in logs if log.get("level") in ["error", "warn"])

        return {
            "session_id": session_id,
            "exported_at": response.get("exportedAt"),
            "total_logs": len(logs),
            "error_count": error_count,
            "diagnostic": diagnostic,
            "summary": f"Session {session_id}: {len(logs)} logs, {error_count} errors/warnings"
        }

    async def get_browser_errors(
        self,
        session_id: Optional[str] = None,
        limit: int = DEFAULT_LOG_LIMIT
    ) -> Dict[str, Any]:
        """Get console errors from a browser session"""
        # Resolve session_id
        if not session_id:
            session_id = self._get_latest_session_id()
            if not session_id:
                return {"error": "No active session found"}

        # Fetch session data from API
        response = await self._request("GET", f"/api/browser-logs/{session_id}")

        if "error" in response:
            return response

        # Filter for errors and warnings
        logs = response.get("logs", [])
        errors = [
            log for log in logs
            if log.get("level") in ["error", "warn"]
        ]

        # Apply limit
        errors = errors[:limit] if limit else errors

        if not errors:
            return {
                "session_id": session_id,
                "errors": [],
                "count": 0,
                "message": "No errors or warnings found in this session"
            }

        return {
            "session_id": session_id,
            "errors": errors,
            "count": len(errors),
            "total_logs": len(logs)
        }

    async def get_browser_network(
        self,
        session_id: Optional[str] = None,
        limit: int = DEFAULT_LOG_LIMIT
    ) -> Dict[str, Any]:
        """Get network logs from a browser session"""
        # Resolve session_id
        if not session_id:
            session_id = self._get_latest_session_id()
            if not session_id:
                return {"error": "No active session found"}

        # Fetch session data from API
        response = await self._request("GET", f"/api/browser-logs/{session_id}")

        if "error" in response:
            return response

        # Check if diagnostic contains network data
        diagnostic = response.get("diagnostic", {})
        network_logs = diagnostic.get("network", [])

        if not network_logs:
            # Fallback: look for logs that mention network/fetch/xhr
            logs = response.get("logs", [])
            network_logs = [
                log for log in logs
                if any(keyword in str(log.get("message", "")).lower()
                      for keyword in ["fetch", "xhr", "request", "response", "http"])
            ]

        # Apply limit
        network_logs = network_logs[:limit] if limit else network_logs

        if not network_logs:
            return {
                "session_id": session_id,
                "network_logs": [],
                "count": 0,
                "message": "No network logs recorded in this session"
            }

        return {
            "session_id": session_id,
            "network_logs": network_logs,
            "count": len(network_logs)
        }

    async def get_server_status(self) -> Dict[str, Any]:
        """Quick health check of the debug server"""
        response = await self._request("GET", "/api/debug/diagnostic")

        if "error" in response:
            return {
                "status": "DOWN",
                "error": response["error"],
                "detail": response.get("detail")
            }

        # Extract just the status
        status = response.get("status", "unknown")
        health = response.get("health", {})

        return {
            "status": status.upper(),
            "health_status": health.get("status"),
            "timestamp": response.get("timestamp"),
            "message": f"Server is {status}"
        }

    async def get_server_diagnostic(self) -> Dict[str, Any]:
        """Get detailed server diagnostics"""
        response = await self._request("GET", "/api/debug/diagnostic")

        if "error" in response:
            return response

        return response

    async def list_workflows(self) -> Dict[str, Any]:
        """List available debug workflows"""
        response = await self._request("GET", "/api/debug/workflows")

        if "error" in response:
            return response

        return response

    async def run_workflow(self, workflow_id: str) -> Dict[str, Any]:
        """Execute a debug workflow"""
        # For now, read the workflow markdown and return its content
        # In the future, this could actually execute the workflow steps

        response = await self._request("GET", "/api/debug/workflows")

        if "error" in response:
            return response

        workflows = response.get("workflows", [])
        workflow = next((w for w in workflows if w.get("id") == workflow_id), None)

        if not workflow:
            return {
                "error": f"Workflow not found: {workflow_id}",
                "available_workflows": [w.get("id") for w in workflows]
            }

        # Read workflow file
        workflow_path = workflow.get("path")
        if workflow_path and Path(workflow_path).exists():
            with open(workflow_path, 'r') as f:
                content = f.read()

            return {
                "workflow_id": workflow_id,
                "title": workflow.get("title"),
                "content": content,
                "message": "Workflow loaded. Follow the steps in the content."
            }

        return {
            "error": "Workflow file not found",
            "workflow": workflow
        }
