"""
Role: Implements hydra_logger.formatters.base functionality for Hydra Logger.
Used By:
 - Internal `hydra_logger` modules importing this component.
Depends On:
 - abc
 - datetime
 - hydra_logger
 - logging
 - re
 - time
 - typing
Notes:
 - Defines output formatting behavior for base.
"""

import logging
import time
from abc import ABC, abstractmethod
from typing import Any, Dict, Optional

from ..types.records import LogRecord
from ..utils.time_utility import TimestampConfig, TimestampFormat, TimestampPrecision

# FormattingEngine removed - no longer needed

# Set up logging for formatters
logger = logging.getLogger(__name__)

class FormatterError(Exception):
    """Custom exception for formatter errors."""

    pass

class BaseFormatter(ABC):
    """Base formatter contract with shared timestamp and validation helpers."""

    def __init__(
        self, name: str = "base", timestamp_config: Optional[TimestampConfig] = None
    ):
        """
        Initialize base formatter.

        Args:
            name: Formatter name for identification
            timestamp_config: Configuration for timestamp formatting
        """
        if not name:
            raise FormatterError("Formatter name cannot be empty")

        self.name = name
        self.timestamp_config = timestamp_config or TimestampConfig(
            format_type=TimestampFormat.RFC3339_MICRO,
            precision=TimestampPrecision.MICROSECONDS,
            timezone_name=None,  # Local timezone
            include_timezone=True,
        )
        self._initialized = True
        self._formatting_errors = []
        self.include_headers = False
        self._headers_written = False
        self._file_id = ""

    def format_timestamp(self, record: LogRecord) -> str:
        """
        Format timestamp from log record using configured timestamp format.

        Caches recent timestamps to avoid expensive datetime conversions.

        Args:
            record: Log record containing timestamp information

        Returns:
            Formatted timestamp string
        """
        from datetime import datetime, timezone

        # Cache timestamp formatting
        # Timestamps within the same millisecond share the same formatted string
        if not hasattr(self, "_timestamp_cache"):
            # Initialize cache: (timestamp_bucket, formatted_string)
            self._timestamp_cache = {}
            self._timestamp_cache_size = 100  # Cache last 100 unique timestamps
            self._timestamp_cache_access = []  # LRU tracking

        # Get timestamp value
        if hasattr(record, "timestamp") and record.timestamp:
            timestamp = record.timestamp
            if isinstance(timestamp, datetime):
                timestamp = timestamp.timestamp()
        else:
            timestamp = time.time()

        # Round to millisecond bucket (1000 messages/sec = 1ms resolution)
        # This allows caching timestamps within the same millisecond
        timestamp_bucket = int(timestamp * 1000)  # Millisecond bucket

        # Check cache first
        if timestamp_bucket in self._timestamp_cache:
            return self._timestamp_cache[timestamp_bucket]

        # Cache miss - format timestamp
        if isinstance(timestamp, (int, float)):
            # Unix timestamp - use local timezone for handlers
            if self.timestamp_config.timezone_name is None:
                dt = datetime.fromtimestamp(timestamp)
            else:
                dt = datetime.fromtimestamp(timestamp, tz=timezone.utc)
        else:
            # Assume it's already a datetime
            dt = timestamp

        formatted = self.timestamp_config.format_timestamp(dt)

        # Update cache (LRU eviction)
        if len(self._timestamp_cache) >= self._timestamp_cache_size:
            # Remove oldest entry
            if self._timestamp_cache_access:
                oldest = self._timestamp_cache_access.pop(0)
                self._timestamp_cache.pop(oldest, None)

        self._timestamp_cache[timestamp_bucket] = formatted
        if timestamp_bucket not in self._timestamp_cache_access:
            self._timestamp_cache_access.append(timestamp_bucket)

        return formatted

    def _strip_ansi_colors(self, text: str) -> str:
        """
        Strip ANSI color codes from text.

        Args:
            text: Text that may contain ANSI color codes

        Returns:
            Clean text without color codes
        """
        try:
            if not text:
                return text

            import re

            # Remove ANSI color codes (ESC[ followed by numbers and optional m)
            ansi_escape = re.compile(r"\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])")
            return ansi_escape.sub("", text)
        except Exception as e:
            logger.warning(f"Failed to strip ANSI colors: {e}")
            return text

    def format(self, record: LogRecord) -> str:
        """
        Format a log record.

        This method provides a unified interface that automatically
        chooses between custom formatting engine and default formatting.

        Args:
            record: Log record to format

        Returns:
            Formatted string representation

        Raises:
            FormatterError: If formatting fails
        """
        if not record:
            raise FormatterError("Log record cannot be None")

        try:
            # Use default formatting
            return self._format_default(record)

        except Exception as e:
            error_msg = f"Formatting failed for record: {e}"
            logger.error(error_msg)
            self._formatting_errors.append(error_msg)
            raise FormatterError(error_msg) from e

    @abstractmethod
    def _format_default(self, record: LogRecord) -> str:
        """
        Default formatting implementation.

        Args:
            record: Log record to format

        Returns:
            Formatted string representation
        """
        pass

    def get_required_extension(self) -> str:
        """
        Get the required file extension for this formatter.

        This enforces industry standards and prevents users from creating
        files with incorrect extensions.

        Returns:
            Required file extension (e.g., '.jsonl', '.gelf', '.csv')
        """
        # Default to .log for text-based formatters
        return ".log"

    def validate_filename(self, filename: str) -> str:
        """
        Validate and correct filename to ensure proper extension.

        Args:
            filename: Original filename

        Returns:
            Corrected filename with proper extension

        Raises:
            FormatterError: If filename cannot be corrected
        """
        required_ext = self.get_required_extension()

        # If filename already has correct extension, return as-is
        if filename.endswith(required_ext):
            return filename

        # If filename has wrong extension, replace it
        if "." in filename:
            base_name = filename.rsplit(".", 1)[0]
            return base_name + required_ext

        # If no extension, add the required one
        return filename + required_ext

    def get_format_name(self) -> str:
        """
        Get formatter name.

        Returns:
            Formatter name
        """
        return self.name

    def is_initialized(self) -> bool:
        """
        Check if formatter is properly initialized.

        Returns:
            True if initialized, False otherwise
        """
        return self._initialized

    def get_config(self) -> Dict[str, Any]:
        """
        Get formatter configuration.

        Returns:
            Configuration dictionary
        """
        try:
            config = {
                "name": self.name,
                "type": self.__class__.__name__,
                "initialized": self._initialized,
                "formatting_errors": self._formatting_errors.copy(),
            }

            return config
        except Exception as e:
            logger.error(f"Failed to get formatter config: {e}")
            return {"name": self.name, "type": self.__class__.__name__, "error": str(e)}

    def get_formatting_errors(self) -> list:
        """
        Get list of formatting errors encountered.

        Returns:
            List of error messages
        """
        return self._formatting_errors.copy()

    def clear_formatting_errors(self) -> None:
        """Clear the list of formatting errors."""
        self._formatting_errors.clear()

    def has_errors(self) -> bool:
        """
        Check if there are any formatting errors.

        Returns:
            True if there are errors
        """
        return len(self._formatting_errors) > 0

    def validate_record(self, record: LogRecord) -> bool:
        """
        Validate if a record can be formatted by this formatter.

        Args:
            record: Log record to validate

        Returns:
            True if valid, False otherwise
        """
        try:
            if not record:
                return False

            # Check if record has required attributes
            required_attrs = ["level", "level_name", "message"]
            for attr in required_attrs:
                if not hasattr(record, attr):
                    return False

            return True
        except Exception as e:
            logger.warning(f"Record validation failed: {e}")
            return False

    def get_stats(self) -> Dict[str, Any]:
        """
        Get formatter statistics.

        Returns:
            Dictionary containing formatter statistics
        """
        return {
            "name": self.name,
            "type": self.__class__.__name__,
            "initialized": self._initialized,
            "formatting_errors": len(self._formatting_errors),
        }

    def format_for_streaming(self, record: LogRecord) -> str:
        """Fallback streaming formatter."""
        return self.format(record)

    def reset_for_new_file(self) -> None:
        """Reset per-file header state."""
        self._headers_written = False

    def set_file_id(self, file_id: str) -> None:
        """Associate formatter state with a file identifier."""
        self._file_id = file_id

    def should_write_headers(self) -> bool:
        """Return True when headers should be emitted for current file."""
        return bool(self.include_headers) and not self._headers_written

    def format_headers(self) -> str:
        """Return a header block when enabled."""
        return ""

    def write_header(self, _file_obj: Any) -> None:
        """Mark headers as written for current file."""
        self._headers_written = True

    def mark_headers_written(self) -> None:
        """Explicitly mark headers as already emitted."""
        self._headers_written = True
