"""
Structured logging system for MCP tools
"""

import json
import logging
import sys
import threading
import time
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, Optional


class StructuredLogger:
    """Structured logger with JSON output support."""

    def __init__(
        self,
        name: str = "web_parser_mcp",
        log_level: str = "INFO",
        json_format: bool = False,
        log_file: Optional[str] = None,
    ):
        self.name = name
        self.json_format = json_format

        # Create logger
        self.logger = logging.getLogger(name)
        self.logger.setLevel(getattr(logging, log_level.upper(), logging.INFO))

        # Remove existing handlers to avoid duplicates
        self.logger.handlers.clear()

        # Create formatter
        if json_format:
            formatter = StructuredJSONFormatter()
        else:
            formatter = StructuredTextFormatter()

        # Console handler
        console_handler = logging.StreamHandler(sys.stdout)
        console_handler.setFormatter(formatter)
        self.logger.addHandler(console_handler)

        # File handler (if specified)
        if log_file:
            file_handler = logging.FileHandler(log_file)
            file_handler.setFormatter(formatter)
            self.logger.addHandler(file_handler)

        # Store context for structured logging
        self._context = threading.local()
        self._context.request_id = None
        self._context.user_id = None
        self._context.session_id = None

    def set_context(
        self,
        request_id: Optional[str] = None,
        user_id: Optional[str] = None,
        session_id: Optional[str] = None,
    ):
        """Set logging context for current thread."""
        self._context.request_id = request_id
        self._context.user_id = user_id
        self._context.session_id = session_id

    def clear_context(self):
        """Clear logging context."""
        self._context.request_id = None
        self._context.user_id = None
        self._context.session_id = None

    def get_context(self) -> dict[str, Any]:
        """Get current logging context."""
        return {
            "request_id": getattr(self._context, "request_id", None),
            "user_id": getattr(self._context, "user_id", None),
            "session_id": getattr(self._context, "session_id", None),
        }

    def log_tool_usage(
        self,
        tool_name: str,
        args: dict[str, Any],
        result: dict[str, Any],
        duration: float,
        success: bool = True,
        error: Optional[str] = None,
    ):
        """Log tool usage with structured data."""
        log_data = {
            "event": "tool_usage",
            "tool_name": tool_name,
            "success": success,
            "duration_seconds": round(duration, 3),
            "args_count": len(args) if args else 0,
            "result_size": len(str(result)) if result else 0,
            "timestamp": datetime.utcnow().isoformat(),
        }

        if error:
            log_data["error"] = error

        # Add context
        context = self.get_context()
        log_data.update({k: v for k, v in context.items() if v is not None})

        # Sanitize sensitive data from args
        safe_args = self._sanitize_args(args)
        log_data["tool_args"] = safe_args

        if success:
            self.logger.info("Tool execution completed", extra={"structured_data": log_data})
        else:
            self.logger.error("Tool execution failed", extra={"structured_data": log_data})

    def log_http_request(
        self,
        method: str,
        url: str,
        status_code: int,
        duration: float,
        cache_hit: bool = False,
        error: Optional[str] = None,
    ):
        """Log HTTP request with structured data."""
        log_data = {
            "event": "http_request",
            "method": method,
            "url": self._sanitize_url(url),
            "status_code": status_code,
            "duration_seconds": round(duration, 3),
            "cache_hit": cache_hit,
            "timestamp": datetime.utcnow().isoformat(),
        }

        if error:
            log_data["error"] = error

        # Add context
        context = self.get_context()
        log_data.update({k: v for k, v in context.items() if v is not None})

        if status_code >= 400:
            self.logger.warning("HTTP request failed", extra={"structured_data": log_data})
        else:
            self.logger.info("HTTP request completed", extra={"structured_data": log_data})

    def log_browser_action(
        self,
        action: str,
        url: Optional[str] = None,
        duration: Optional[float] = None,
        success: bool = True,
        error: Optional[str] = None,
    ):
        """Log browser action with structured data."""
        log_data = {
            "event": "browser_action",
            "action": action,
            "success": success,
            "timestamp": datetime.utcnow().isoformat(),
        }

        if url:
            log_data["url"] = self._sanitize_url(url)
        if duration:
            log_data["duration_seconds"] = round(duration, 3)
        if error:
            log_data["error"] = error

        # Add context
        context = self.get_context()
        log_data.update({k: v for k, v in context.items() if v is not None})

        if success:
            self.logger.info("Browser action completed", extra={"structured_data": log_data})
        else:
            self.logger.error("Browser action failed", extra={"structured_data": log_data})

    def log_cache_operation(
        self, operation: str, key: str, hit: bool = False, size: Optional[int] = None
    ):
        """Log cache operation."""
        log_data = {
            "event": "cache_operation",
            "operation": operation,
            "key_hash": hash(key) % 1000000,  # Log hash instead of actual key
            "hit": hit,
            "timestamp": datetime.utcnow().isoformat(),
        }

        if size is not None:
            log_data["cache_size"] = size

        self.logger.debug("Cache operation", extra={"structured_data": log_data})

    def log_performance_metric(
        self, name: str, value: float, labels: Optional[dict[str, str]] = None
    ):
        """Log performance metric."""
        log_data = {
            "event": "performance_metric",
            "metric_name": name,
            "value": value,
            "timestamp": datetime.utcnow().isoformat(),
        }

        if labels:
            log_data["labels"] = labels

        # Add context
        context = self.get_context()
        log_data.update({k: v for k, v in context.items() if v is not None})

        self.logger.info("Performance metric recorded", extra={"structured_data": log_data})

    def _sanitize_url(self, url: str) -> str:
        """Sanitize URL for logging (remove sensitive parameters)."""
        try:
            from urllib.parse import parse_qs, urlencode, urlparse, urlunparse

            parsed = urlparse(url)
            query_params = parse_qs(parsed.query)

            # Remove sensitive parameters
            sensitive_params = {"password", "token", "key", "secret", "auth"}
            sanitized_params = {
                k: v for k, v in query_params.items() if k.lower() not in sensitive_params
            }

            # Replace sensitive values with placeholders
            for key in sensitive_params:
                if key in query_params:
                    sanitized_params[f"{key}_masked"] = ["***"]

            sanitized_query = urlencode(sanitized_params, doseq=True)
            sanitized_url = urlunparse(
                (
                    parsed.scheme,
                    parsed.netloc,
                    parsed.path,
                    parsed.params,
                    sanitized_query,
                    parsed.fragment,
                )
            )

            return sanitized_url
        except Exception:
            return url

    def _sanitize_args(self, args: dict[str, Any]) -> dict[str, Any]:
        """Sanitize tool arguments for logging."""
        if not args:
            return {}

        sanitized = {}
        sensitive_keys = {
            "password",
            "token",
            "key",
            "secret",
            "auth",
            "cookie",
            "authorization",
            "credentials",
            "session",
        }

        for key, value in args.items():
            if key.lower() in sensitive_keys:
                sanitized[f"{key}_masked"] = "***"
            elif isinstance(value, dict):
                sanitized[key] = self._sanitize_args(value)
            elif isinstance(value, str) and len(value) > 100:
                # Truncate long strings
                sanitized[key] = value[:100] + "..."
            else:
                sanitized[key] = value

        return sanitized


class StructuredJSONFormatter(logging.Formatter):
    """JSON formatter for structured logging."""

    def format(self, record):
        log_entry = {
            "timestamp": datetime.utcnow().isoformat(),
            "level": record.levelname,
            "logger": record.name,
            "message": record.getMessage(),
        }

        # Add structured data if present
        if hasattr(record, "structured_data"):
            log_entry.update(record.structured_data)

        # Add exception info if present
        if record.exc_info:
            log_entry["exception"] = self.formatException(record.exc_info)

        return json.dumps(log_entry, ensure_ascii=False)


class StructuredTextFormatter(logging.Formatter):
    """Human-readable text formatter with structured data support."""

    def format(self, record):
        # Basic log format
        log_message = super().format(record)

        # Add structured data if present
        if hasattr(record, "structured_data"):
            structured_data = record.structured_data
            if structured_data.get("event") == "tool_usage":
                log_message += f" [tool={structured_data.get('tool_name')}]"
                log_message += f" [duration={structured_data.get('duration_seconds')}s]"
                log_message += f" [success={structured_data.get('success')}]"
            elif structured_data.get("event") == "http_request":
                log_message += f" [{structured_data.get('method')} {structured_data.get('url')}]"
                log_message += f" [status={structured_data.get('status_code')}]"
                log_message += f" [duration={structured_data.get('duration_seconds')}s]"
            elif structured_data.get("event") == "browser_action":
                log_message += f" [action={structured_data.get('action')}]"
                if structured_data.get("url"):
                    log_message += f" [url={structured_data.get('url')}]"

        return log_message


# Global logger instance
_structured_logger = StructuredLogger()


def get_structured_logger() -> StructuredLogger:
    """Get global structured logger."""
    return _structured_logger


def setup_logging(
    log_level: str = "INFO", json_format: bool = False, log_file: Optional[str] = None
) -> StructuredLogger:
    """Setup global logging configuration."""
    global _structured_logger
    _structured_logger = StructuredLogger(
        name="web_parser_mcp",
        log_level=log_level,
        json_format=json_format,
        log_file=log_file,
    )
    return _structured_logger


# Convenience functions for quick logging
def log_tool_start(tool_name: str, args: dict[str, Any]) -> float:
    """Log tool execution start and return start time."""
    logger = get_structured_logger()
    start_time = time.time()

    # Create a compact log entry for start
    log_data = {
        "event": "tool_start",
        "tool_name": tool_name,
        "args_count": len(args) if args else 0,
        "timestamp": datetime.utcnow().isoformat(),
    }

    logger.logger.info(f"Starting {tool_name}", extra={"structured_data": log_data})
    return start_time


def log_tool_end(
    tool_name: str,
    start_time: float,
    result: dict[str, Any],
    success: bool = True,
    error: Optional[str] = None,
):
    """Log tool execution end."""
    logger = get_structured_logger()
    duration = time.time() - start_time

    logger.log_tool_usage(tool_name, {}, result, duration, success, error)


def log_http_request(
    method: str,
    url: str,
    status_code: int,
    duration: float,
    cache_hit: bool = False,
    error: Optional[str] = None,
):
    """Log HTTP request."""
    logger = get_structured_logger()
    logger.log_http_request(method, url, status_code, duration, cache_hit, error)


def log_browser_action(
    action: str,
    url: Optional[str] = None,
    duration: Optional[float] = None,
    success: bool = True,
    error: Optional[str] = None,
):
    """Log browser action."""
    logger = get_structured_logger()
    logger.log_browser_action(action, url, duration, success, error)


def log_cache_operation(operation: str, key: str, hit: bool = False, size: Optional[int] = None):
    """Log cache operation."""
    logger = get_structured_logger()
    logger.log_cache_operation(operation, key, hit, size)


def log_performance_metric(name: str, value: float, labels: Optional[dict[str, str]] = None):
    """Log performance metric."""
    logger = get_structured_logger()
    logger.log_performance_metric(name, value, labels)


# Context manager for request logging
class RequestContext:
    """Context manager for logging request context."""

    def __init__(
        self,
        request_id: Optional[str] = None,
        user_id: Optional[str] = None,
        session_id: Optional[str] = None,
    ):
        self.logger = get_structured_logger()
        self.request_id = request_id
        self.user_id = user_id
        self.session_id = session_id

    def __enter__(self):
        self.logger.set_context(self.request_id, self.user_id, self.session_id)
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.logger.clear_context()


# Setup default logging
setup_logging()
