"""
Role: Implements hydra_logger.formatters.structured_formatter functionality for Hydra Logger.
Used By:
 - Internal `hydra_logger` modules importing this component.
Depends On:
 - csv
 - hydra_logger
 - io
 - json
 - os
 - psutil
 - socket
 - sys
 - ...
Notes:
 - Defines output formatting behavior for structured formatter.
"""

import csv
import io
import os
from typing import List, Optional

from ..core.constants import CSV_HEADERS
from ..types.records import LogRecord
from ..utils.time_utility import TimestampConfig, TimestampFormat, TimestampPrecision
from .base import BaseFormatter


def _get_timestamp_config() -> TimestampConfig:
    """
    Get timestamp configuration based on environment.

    Returns:
        Timestamp configuration
    """
    import os

    # Check if we're in production environment
    is_production = os.environ.get("ENVIRONMENT", "").lower() in ["production", "prod"]

    if is_production:
        # Production: UTC, microsecond precision, RFC3339 format
        return TimestampConfig(
            format_type=TimestampFormat.RFC3339_MICRO,
            precision=TimestampPrecision.MICROSECONDS,
            timezone_name="UTC",
            include_timezone=True,
        )
    else:
        # Development: Local timezone, second precision, human readable
        return TimestampConfig(
            format_type=TimestampFormat.HUMAN_READABLE,
            precision=TimestampPrecision.SECONDS,
            timezone_name=None,  # Local timezone
            include_timezone=False,
        )


class CsvFormatter(BaseFormatter):
    """CSV format formatter for structured logging with proper headers and quoting."""

    def __init__(
        self,
        include_headers: bool = True,
        timestamp_config: Optional[TimestampConfig] = None,
    ):
        """
        Initialize CSV formatter.

        Args:
            include_headers: Whether to include CSV headers
            timestamp_config: Configuration for timestamp formatting
        """
        # Set timestamp config if not provided
        if timestamp_config is None:
            timestamp_config = _get_timestamp_config()
        super().__init__("csv", timestamp_config=timestamp_config)
        self.include_headers = include_headers
        self._headers_written = False
        self._file_headers_written = set()  # Track headers per file

        # Simplified formatter - no performance optimization
        self._format_func = self._format_default

    def get_headers(self) -> List[str]:
        """Get CSV headers based on default configuration."""
        # Use default headers for backward compatibility

        return CSV_HEADERS

    def format_headers(self) -> str:
        """Format CSV headers as a string."""
        output = io.StringIO()
        writer = csv.writer(output)
        writer.writerow(self.get_headers())
        return output.getvalue().rstrip("\n")

    def format(self, record: LogRecord) -> str:
        """
        Format record as CSV line with proper quoting.

        Args:
            record: Log record to format

        Returns:
            CSV formatted string
        """
        # Use default formatting for backward compatibility
        return self._format_default(record)

    def _format_default(self, record: LogRecord) -> str:
        """
        CSV formatting implementation with minimal overhead.

        Args:
            record: Log record to format

        Returns:
            CSV formatted string
        """
        # Pre-format timestamp once
        timestamp = self.format_timestamp(record)

        # Build row with minimal string operations - avoid list creation
        # Use direct string building
        row_parts = [
            timestamp,
            record.level_name,
            record.layer or "",
            record.file_name or "",
            record.function_name or "",
            record.message or "",
            str(record.level),
            record.logger_name,
            str(record.line_number or ""),
        ]

        # Handle structured data fields efficiently - avoid JSON if possible
        structured_data = {}
        if record.extra:
            structured_data.update(record.extra)
        if record.context:
            structured_data.update(record.context)

        if structured_data:
            # Simple string representation for better performance
            structured_str = str(structured_data)
        else:
            structured_str = ""

        row_parts.append(structured_str)

        # CSV formatting - avoid io.StringIO overhead
        # Use direct string manipulation
        result_parts = []
        for field in row_parts:
            field_str = str(field)
            # Simple CSV escaping - only quote if contains comma, quote, or newline
            if (
                "," in field_str
                or '"' in field_str
                or "\n" in field_str
                or "\r" in field_str
            ):
                # Escape quotes and wrap in quotes
                escaped = field_str.replace('"', '""')
                result_parts.append(f'"{escaped}"')
            else:
                result_parts.append(field_str)

        return ",".join(result_parts)

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

        Returns:
            '.csv' - Industry standard for CSV format
        """
        return ".csv"

    def should_write_headers(self, file_path: Optional[str] = None) -> bool:
        """
        Check if headers should be written for a specific file.

        Args:
            file_path: Path to the file (optional)

        Returns:
            True if headers should be written
        """
        if not self.include_headers:
            return False

        if file_path is None:
            # If no file path, write headers once per formatter instance
            return not self._headers_written

        # Check if headers were already written to this file
        if file_path in self._file_headers_written:
            return False

        # If file exists and has content, assume headers are already there
        if os.path.exists(file_path) and os.path.getsize(file_path) > 0:
            # Mark as having headers to avoid future checks
            self._file_headers_written.add(file_path)
            return False

        # File doesn't exist or is empty, write headers
        return True

    def mark_headers_written(self, file_path: Optional[str] = None) -> None:
        """
        Mark headers as written for a specific file.

        Args:
            file_path: Path to the file (optional)
        """
        if file_path is None:
            self._headers_written = True
        else:
            self._file_headers_written.add(file_path)


class SyslogFormatter(BaseFormatter):
    """Syslog format formatter for system logging."""

    def __init__(self, facility: int = 1, app_name: Optional[str] = None):
        """
        Initialize syslog formatter.

        Args:
            facility: Syslog facility number
            app_name: Application name (auto-detected if None)
        """
        super().__init__("syslog")
        self.facility = facility
        self.app_name = app_name or self._detect_app_name()

        # Syslog severity mapping
        self.severity_map = {
            0: 7,  # NOTSET -> DEBUG
            10: 7,  # DEBUG -> DEBUG
            20: 6,  # INFO -> INFO
            30: 4,  # WARNING -> WARNING
            40: 3,  # ERROR -> ERROR
            50: 2,  # CRITICAL -> CRITICAL
        }

        # Simplified formatter - no performance optimization
        self._format_func = self._format_default

    def _detect_app_name(self) -> str:
        """
        Auto-detect application name from various sources.

        Returns:
            Detected application name
        """
        import os
        import sys

        # Try to get from environment variable first
        app_name = os.environ.get("APP_NAME") or os.environ.get("SERVICE_NAME")
        if app_name:
            return app_name

        # Try to get from sys.argv
        if sys.argv and len(sys.argv) > 0:
            script_name = os.path.basename(sys.argv[0])
            if script_name and script_name != "-c":  # Not from -c flag
                return script_name.replace(".py", "")

        # Try to get from process name
        try:
            import psutil

            process = psutil.Process()
            return process.name()
        except (ImportError, Exception):
            pass

        # Fallback to generic name
        return "hydra-logger"

    def format(self, record: LogRecord) -> str:
        """
        Syslog message formatting with minimal overhead.

        Args:
            record: Log record to format

        Returns:
            Syslog formatted string
        """
        # Pre-calculate priority (facility * 8 + severity)
        severity = self.severity_map.get(record.level, 6)  # Default to INFO
        priority = self.facility * 8 + severity

        # Pre-format timestamp once
        timestamp = self.format_timestamp(record)

        # Build message with minimal string operations
        if record.file_name and record.function_name:
            return (
                f"<{priority}> {timestamp} {self.app_name} {record.level_name} "
                f"{record.layer} {record.message} "
                f"{record.file_name}:{record.function_name}:{record.line_number}"
            )
        return (
            f"<{priority}> {timestamp} {self.app_name} "
            f"{record.level_name} {record.layer} {record.message}"
        )

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

        Returns:
            '.log' - Industry standard for syslog format files
        """
        return ".log"

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

        Args:
            record: Log record to format

        Returns:
            Formatted string representation
        """
        return self.format(record)


class GelfFormatter(BaseFormatter):
    """GELF format formatter for Graylog."""

    def __init__(self, host: Optional[str] = None, version: str = "1.1"):
        """
        Initialize GELF formatter.

        Args:
            host: Hostname (auto-detected if None)
            version: GELF version
        """
        super().__init__("gelf")
        self.host = host or self._detect_hostname()
        self.version = version

    def _detect_hostname(self) -> str:
        """
        Auto-detect hostname from various sources.

        Returns:
            Detected hostname
        """
        import os
        import socket

        # Try to get from environment variable first
        hostname = os.environ.get("HOSTNAME") or os.environ.get("HOST")
        if hostname:
            return hostname

        # Try socket.gethostname()
        try:
            hostname = socket.gethostname()
            if hostname and hostname != "localhost":
                return hostname
        except Exception:
            pass

        # Try socket.getfqdn()
        try:
            fqdn = socket.getfqdn()
            if fqdn and fqdn != "localhost":
                return fqdn
        except Exception:
            pass

        # Fallback to localhost
        return "localhost"

    def format(self, record: LogRecord) -> str:
        """
        GELF message formatting with minimal overhead.

        Args:
            record: Log record to format

        Returns:
            GELF formatted string
        """
        import json

        # Pre-format timestamp once
        timestamp = self.format_timestamp(record)

        # GELF level mapping (0-7, where 0 is most severe) - use dict.get for
        # performance
        level_map = {0: 7, 10: 7, 20: 6, 30: 4, 40: 3, 50: 2}

        # Build GELF message with minimal dictionary operations
        gelf_msg = {
            "version": self.version,
            "host": self.host,
            "short_message": record.message,
            "timestamp": timestamp,
            "level": level_map.get(record.level, 6),
            "_logger_name": record.logger_name,
            "_layer": record.layer or "",
            "_file_name": record.file_name or "",
            "_function_name": record.function_name or "",
            "_line_number": record.line_number or 0,
        }

        # Add structured data fields efficiently
        if record.extra:
            gelf_msg["_extra"] = record.extra
        if record.context:
            gelf_msg["_context"] = record.context

        return json.dumps(gelf_msg, separators=(",", ":"))

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

        Returns:
            '.gelf' - Industry standard for Graylog Extended Log Format
        """
        return ".gelf"

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

        Args:
            record: Log record to format

        Returns:
            Formatted string representation
        """
        return self.format(record)


class LogstashFormatter(BaseFormatter):
    """Logstash format formatter for Elasticsearch."""

    def __init__(self, type_name: Optional[str] = None, tags: Optional[list] = None):
        """
        Initialize Logstash formatter.

        Args:
            type_name: Log type name (auto-detected if None)
            tags: List of tags (auto-detected if None)
        """
        super().__init__("logstash")
        self.type_name = type_name or self._detect_log_type()
        self.tags = tags or self._detect_tags()

    def _detect_log_type(self) -> str:
        """
        Auto-detect log type from various sources.

        Returns:
            Detected log type
        """
        import os
        import sys

        # Try to get from environment variable first
        log_type = os.environ.get("LOG_TYPE") or os.environ.get("SERVICE_TYPE")
        if log_type:
            return log_type

        # Try to detect from sys.argv
        if sys.argv and len(sys.argv) > 0:
            script_name = os.path.basename(sys.argv[0])
            if script_name and script_name != "-c":
                # Extract meaningful part
                if "api" in script_name.lower():
                    return "api-logs"
                elif "web" in script_name.lower():
                    return "web-logs"
                elif "worker" in script_name.lower():
                    return "worker-logs"
                elif "cron" in script_name.lower():
                    return "cron-logs"
                else:
                    return f"{script_name.replace('.py', '')}-logs"

        # Fallback to generic
        return "application-logs"

    def _detect_tags(self) -> list:
        """
        Auto-detect tags from environment and context.

        Returns:
            List of detected tags
        """
        import os

        tags = []

        # Environment tags
        env = os.environ.get("ENVIRONMENT", "development")
        tags.append(env)

        # Service tags
        service = os.environ.get("SERVICE_NAME") or os.environ.get("APP_NAME")
        if service:
            tags.append(service)

        # Platform tags
        platform = os.environ.get("PLATFORM", "python")
        tags.append(platform)

        # Add common tags
        tags.extend(["logstash", "structured"])

        return tags

    def format(self, record: LogRecord) -> str:
        """
        Logstash message formatting with minimal overhead.

        Args:
            record: Log record to format

        Returns:
            Logstash formatted string
        """
        import json

        # Pre-format timestamp once
        timestamp = self.format_timestamp(record)

        # Build Logstash message with minimal dictionary operations
        fields = {
            "file_name": record.file_name or "",
            "function_name": record.function_name or "",
            "line_number": record.line_number or 0,
        }

        # Add structured data fields efficiently
        if record.extra:
            fields.update(record.extra)
        if record.context:
            fields.update(record.context)

        logstash_msg = {
            "@timestamp": timestamp,
            "@version": "1",
            "message": record.message,
            "level": record.level_name,
            "logger_name": record.logger_name,
            "layer": record.layer or "",
            "type": self.type_name,
            "tags": self.tags,
            "fields": fields,
        }

        return json.dumps(logstash_msg, separators=(",", ":"))

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

        Returns:
            '.log' - Industry standard for logstash format files
        """
        return ".log"

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

        Args:
            record: Log record to format

        Returns:
            Formatted string representation
        """
        return self.format(record)
