"""
API Logger with Rich
Beautiful console logging for API requests and responses

Installation:
    pip install rich
"""

from __future__ import annotations

import time
from dataclasses import dataclass, field
from typing import Any, Dict, Optional

from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich.text import Text


@dataclass
class RequestLog:
    """Request log data."""

    method: str
    url: str
    headers: Optional[Dict[str, str]] = None
    body: Optional[Any] = None
    timestamp: float = field(default_factory=time.time)


@dataclass
class ResponseLog:
    """Response log data."""

    status: int
    status_text: str
    data: Optional[Any] = None
    duration: float = 0.0
    timestamp: float = field(default_factory=time.time)


@dataclass
class ErrorLog:
    """Error log data."""

    message: str
    status_code: Optional[int] = None
    field_errors: Optional[Dict[str, list[str]]] = None
    duration: float = 0.0
    timestamp: float = field(default_factory=time.time)


@dataclass
class LoggerConfig:
    """Logger configuration."""

    enabled: bool = True
    log_requests: bool = True
    log_responses: bool = True
    log_errors: bool = True
    log_bodies: bool = True
    log_headers: bool = False
    console: Optional[Console] = None


# Sensitive header names to filter out
SENSITIVE_HEADERS = [
    "authorization",
    "cookie",
    "set-cookie",
    "x-api-key",
    "x-csrf-token",
]


class APILogger:
    """API Logger class."""

    def __init__(self, config: Optional[LoggerConfig] = None):
        """Initialize logger."""
        self.config = config or LoggerConfig()
        self.console = self.config.console or Console()

    def enable(self) -> None:
        """Enable logging."""
        self.config.enabled = True

    def disable(self) -> None:
        """Disable logging."""
        self.config.enabled = False

    def set_config(self, **kwargs: Any) -> None:
        """Update configuration."""
        for key, value in kwargs.items():
            if hasattr(self.config, key):
                setattr(self.config, key, value)

    def _filter_headers(self, headers: Optional[Dict[str, str]]) -> Dict[str, str]:
        """Filter sensitive headers."""
        if not headers:
            return {}

        filtered = {}
        for key, value in headers.items():
            if key.lower() in SENSITIVE_HEADERS:
                filtered[key] = "***"
            else:
                filtered[key] = value

        return filtered

    def log_request(self, request: RequestLog) -> None:
        """Log request."""
        if not self.config.enabled or not self.config.log_requests:
            return

        # Create request info
        text = Text()
        text.append("→ ", style="bold blue")
        text.append(request.method, style="bold yellow")
        text.append(" ", style="")
        text.append(request.url, style="cyan")

        self.console.print(text)

        if self.config.log_headers and request.headers:
            headers = self._filter_headers(request.headers)
            self.console.print("  Headers:", style="dim")
            for key, value in headers.items():
                self.console.print(f"    {key}: {value}", style="dim")

        if self.config.log_bodies and request.body:
            self.console.print("  Body:", style="dim")
            self.console.print(request.body, style="dim")

    def log_response(self, request: RequestLog, response: ResponseLog) -> None:
        """Log response."""
        if not self.config.enabled or not self.config.log_responses:
            return

        # Determine color based on status
        if response.status >= 500:
            status_style = "bold red"
        elif response.status >= 400:
            status_style = "bold yellow"
        elif response.status >= 300:
            status_style = "bold cyan"
        else:
            status_style = "bold green"

        # Create response info
        text = Text()
        text.append("← ", style="bold green")
        text.append(request.method, style="bold yellow")
        text.append(" ", style="")
        text.append(request.url, style="cyan")
        text.append(" ", style="")
        text.append(str(response.status), style=status_style)
        text.append(" ", style="")
        text.append(response.status_text, style=status_style)
        text.append(f" ({response.duration:.0f}ms)", style="dim")

        self.console.print(text)

        if self.config.log_bodies and response.data:
            self.console.print("  Response:", style="dim")
            self.console.print(response.data, style="dim")

    def log_error(self, request: RequestLog, error: ErrorLog) -> None:
        """Log error."""
        if not self.config.enabled or not self.config.log_errors:
            return

        # Create error header
        text = Text()
        text.append("✗ ", style="bold red")
        text.append(request.method, style="bold yellow")
        text.append(" ", style="")
        text.append(request.url, style="cyan")
        text.append(" ", style="")
        text.append(
            str(error.status_code) if error.status_code else "Network",
            style="bold red",
        )
        text.append(" Error", style="bold red")
        text.append(f" ({error.duration:.0f}ms)", style="dim")

        self.console.print(text)
        self.console.print(f"  Message: {error.message}", style="red")

        if error.field_errors:
            self.console.print("  Field Errors:", style="red")
            for field, errors in error.field_errors.items():
                for err in errors:
                    self.console.print(f"    • {field}: {err}", style="red dim")

    def info(self, message: str, **kwargs: Any) -> None:
        """Log info message."""
        if not self.config.enabled:
            return
        self.console.print(f"ℹ {message}", style="blue", **kwargs)

    def warn(self, message: str, **kwargs: Any) -> None:
        """Log warning message."""
        if not self.config.enabled:
            return
        self.console.print(f"⚠ {message}", style="yellow", **kwargs)

    def error(self, message: str, **kwargs: Any) -> None:
        """Log error message."""
        if not self.config.enabled:
            return
        self.console.print(f"✗ {message}", style="red", **kwargs)

    def success(self, message: str, **kwargs: Any) -> None:
        """Log success message."""
        if not self.config.enabled:
            return
        self.console.print(f"✓ {message}", style="green", **kwargs)

    def debug(self, message: str, **kwargs: Any) -> None:
        """Log debug message."""
        if not self.config.enabled:
            return
        self.console.print(f"🔍 {message}", style="dim", **kwargs)

    def panel(self, content: Any, title: str, style: str = "blue") -> None:
        """Log content in a panel."""
        if not self.config.enabled:
            return
        self.console.print(Panel(content, title=title, border_style=style))

    def table(
        self,
        headers: list[str],
        rows: list[list[Any]],
        title: Optional[str] = None,
    ) -> None:
        """Log data in a table."""
        if not self.config.enabled:
            return

        table = Table(title=title)
        for header in headers:
            table.add_column(header, style="cyan")

        for row in rows:
            table.add_row(*[str(cell) for cell in row])

        self.console.print(table)


# Default logger instance
default_logger = APILogger()
