from typing import Optional
"""
Performance logging utilities for tracking timing and metrics.
"""

import time

from .core import FailSafeLogger


class PerformanceLogger:
    """
    Specialized logger for performance metrics and timing.
    """

    def __init__(self, logger: FailSafeLogger):
        self.logger = logger

    def log_operation_time(self, operation: str, duration_ms: float, **context):
        """Log operation timing with context."""
        formatted_duration = self._format_duration(duration_ms)
        self.logger.perf(
            f"{operation} completed in {formatted_duration}",
            duration_ms=duration_ms,
            **context,
        )

    def log_throughput(self, operation: str, items: int, duration_ms: float, **context):
        """Log throughput metrics."""
        if duration_ms > 0:
            items_per_sec = (items / duration_ms) * 1000
            self.logger.perf(
                f"{operation} processed {items:,} items in {self._format_duration(duration_ms)} "
                f"({items_per_sec:.1f} items/sec)",
                items=items,
                duration_ms=duration_ms,
                throughput=items_per_sec,
                **context,
            )
        else:
            self.logger.perf(
                f"{operation} processed {items:,} items instantly",
                items=items,
                duration_ms=duration_ms,
                **context,
            )

    def log_memory_usage(self, operation: str, memory_mb: float, **context):
        """Log memory usage metrics."""
        self.logger.perf(
            f"{operation} memory usage: {memory_mb:.1f} MB",
            memory_mb=memory_mb,
            **context,
        )

    def log_cost_metrics(
        self, operation: str, cost: float, currency: str = "USD", **context
    ):
        """Log cost-related metrics."""
        self.logger.perf(
            f"{operation} cost: {currency} {cost:,.2f}",
            cost=cost,
            currency=currency,
            **context,
        )

    def log_data_size(
        self, operation: str, rows: int, file_size_mb: Optional[float] = None, **context
    ):
        """Log data size metrics."""
        message = f"{operation} data: {rows:,} rows"
        if file_size_mb is not None:
            message += f", {file_size_mb:.1f} MB"

        self.logger.perf(message, rows=rows, file_size_mb=file_size_mb, **context)

    @staticmethod
    def _format_duration(duration_ms: float) -> str:
        """Format duration in human-readable format."""
        if duration_ms < 1000:
            return f"{duration_ms:.0f}ms"
        elif duration_ms < 60000:
            return f"{duration_ms / 1000:.1f}s"
        elif duration_ms < 3600000:
            minutes = duration_ms / 60000
            return f"{minutes:.0f}m {(duration_ms % 60000) / 1000:.0f}s"
        else:
            hours = duration_ms / 3600000
            minutes = (duration_ms % 3600000) / 60000
            return f"{hours:.0f}h {minutes:.0f}m"


class PerformanceTimer:
    """
    Context manager for timing operations with automatic logging.
    """

    def __init__(self, logger: FailSafeLogger, operation: str, **base_context):
        self.logger = logger
        self.operation = operation
        self.base_context = base_context
        self.start_time = None
        self.additional_context = {}

    def __enter__(self):
        self.start_time = time.time()
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.start_time:
            duration_ms = (time.time() - self.start_time) * 1000

            # Combine all context
            full_context = {**self.base_context, **self.additional_context}

            # Log the timing
            perf_logger = PerformanceLogger(self.logger)
            perf_logger.log_operation_time(self.operation, duration_ms, **full_context)

    def add_context(self, **context):
        """Add additional context to be logged with the timing result."""
        self.additional_context.update(context)

    def log_checkpoint(self, checkpoint: str, **context):
        """Log an intermediate checkpoint within the timed operation."""
        if self.start_time:
            elapsed_ms = (time.time() - self.start_time) * 1000
            self.logger.debug(
                f"{self.operation} checkpoint: {checkpoint}",
                elapsed_ms=elapsed_ms,
                **context,
            )
