"""
Logging system for rateloader.

Creates a single unified rotating logger as per ADR: Unified Logging System:
- rateloader.log (unified log with component prefixes)

Uses rotating file handlers and ensures log/ folder exists next to executable.
Component prefixes: [EXPORT], [PRICE], [RATELOADER], [GUI], [ORACLE], [SCHEDULER], [HTTP], [QUEUE]
"""

import os
import logging
import logging.handlers
from typing import Optional


class LoggerManager:
    """Manages unified logger for the rateloader application."""

    def __init__(self, log_dir: str = "log"):
        """
        Initialize logger manager.

        Args:
            log_dir: Directory where log files will be stored
        """
        self.log_dir = log_dir
        self._ensure_log_dir_exists()

        # Single unified log file
        self.log_file = "rateloader.log"

        self._logger = None
        self._setup_unified_logger()

    def _ensure_log_dir_exists(self) -> None:
        """Ensure the log directory exists."""
        if not os.path.exists(self.log_dir):
            os.makedirs(self.log_dir)

    def _setup_unified_logger(self) -> None:
        """Set up the unified logger with rotating file handler."""
        # Create logger
        self._logger = logging.getLogger("rateloader")
        self._logger.setLevel(logging.INFO)

        # Clear existing handlers to avoid duplicates
        self._logger.handlers.clear()

        # Create rotating file handler
        # Rotate when file reaches 5MB, keep 5 backup files
        log_path = os.path.join(self.log_dir, self.log_file)
        handler = logging.handlers.RotatingFileHandler(
            log_path, maxBytes=5 * 1024 * 1024, backupCount=5, encoding="utf-8"  # 5MB
        )

        # Create formatter with component prefix
        formatter = logging.Formatter(
            "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
            datefmt="%Y-%m-%d %H:%M:%S",
        )
        handler.setFormatter(formatter)

        # Add handler to logger
        self._logger.addHandler(handler)

    def _get_component_logger(self, component: str) -> logging.Logger:
        """
        Get a logger with component prefix.

        Args:
            component: Component name for prefix

        Returns:
            Logger instance with component prefix
        """
        # Create a logger adapter that adds component prefix
        class ComponentLoggerAdapter(logging.LoggerAdapter):
            def process(self, msg, kwargs):
                return f"[{component}] {msg}", kwargs

        return ComponentLoggerAdapter(self._logger, {})

    def get_logger(self, component: str = "RATELOADER") -> logging.Logger:
        """
        Get a logger with component prefix.

        Args:
            component: Component name for prefix (EXPORT, PRICE, RATELOADER, GUI, ORACLE, SCHEDULER, HTTP, QUEUE)

        Returns:
            Logger instance with component prefix
        """
        return self._get_component_logger(component)

    def get_hotellabexport_logger(self) -> logging.Logger:
        """
        Get the export logger (CSV/email flow) with [EXPORT] prefix.

        Returns:
            Logger instance for CSV/email flow
        """
        return self.get_logger("EXPORT")

    def get_hotellabpriceexport_logger(self) -> logging.Logger:
        """
        Get the price export logger (API export flow) with [PRICE] prefix.

        Returns:
            Logger instance for API export flow
        """
        return self.get_logger("PRICE")

    def get_rateloader_logger(self) -> logging.Logger:
        """
        Get the rateloader logger (HTTP server + scheduler + queue) with [RATELOADER] prefix.

        Returns:
            Logger instance for HTTP server + scheduler + queue
        """
        return self.get_logger("RATELOADER")

    def get_gui_logger(self) -> logging.Logger:
        """
        Get the GUI logger with [GUI] prefix.

        Returns:
            Logger instance for GUI operations
        """
        return self.get_logger("GUI")

    def get_oracle_logger(self) -> logging.Logger:
        """
        Get the Oracle logger with [ORACLE] prefix.

        Returns:
            Logger instance for Oracle operations
        """
        return self.get_logger("ORACLE")

    def get_scheduler_logger(self) -> logging.Logger:
        """
        Get the scheduler logger with [SCHEDULER] prefix.

        Returns:
            Logger instance for scheduler operations
        """
        return self.get_logger("SCHEDULER")

    def get_http_logger(self) -> logging.Logger:
        """
        Get the HTTP logger with [HTTP] prefix.

        Returns:
            Logger instance for HTTP server operations
        """
        return self.get_logger("HTTP")

    def get_queue_logger(self) -> logging.Logger:
        """
        Get the queue logger with [QUEUE] prefix.

        Returns:
            Logger instance for task queue operations
        """
        return self.get_logger("QUEUE")

    def log_exception(
        self, component: str, message: str, exception: Exception
    ) -> None:
        """
        Log an exception with full traceback.

        Args:
            component: Component name for prefix
            message: Message to log with the exception
            exception: Exception to log
        """
        logger = self.get_logger(component)
        logger.error(f"{message}: {str(exception)}", exc_info=True)

    def log_info(self, component: str, message: str) -> None:
        """
        Log an info message.

        Args:
            component: Component name for prefix
            message: Message to log
        """
        logger = self.get_logger(component)
        logger.info(message)

    def log_warning(self, component: str, message: str) -> None:
        """
        Log a warning message.

        Args:
            component: Component name for prefix
            message: Message to log
        """
        logger = self.get_logger(component)
        logger.warning(message)

    def log_error(self, component: str, message: str) -> None:
        """
        Log an error message.

        Args:
            component: Component name for prefix
            message: Message to log
        """
        logger = self.get_logger(component)
        logger.error(message)

    def log_debug(self, component: str, message: str) -> None:
        """
        Log a debug message.

        Args:
            component: Component name for prefix
            message: Message to log
        """
        logger = self.get_logger(component)
        logger.debug(message)


# Global logger manager instance
_logger_manager = None


def get_logger_manager() -> LoggerManager:
    """
    Get the global logger manager instance.

    Returns:
        Global LoggerManager instance
    """
    global _logger_manager
    if _logger_manager is None:
        _logger_manager = LoggerManager()
    return _logger_manager


def get_hotellabexport_logger() -> logging.Logger:
    """
    Get the export logger (CSV/email flow) with [EXPORT] prefix.

    Returns:
        Logger instance for CSV/email flow
    """
    return get_logger_manager().get_hotellabexport_logger()


def get_hotellabpriceexport_logger() -> logging.Logger:
    """
    Get the price export logger (API export flow) with [PRICE] prefix.

    Returns:
        Logger instance for API export flow
    """
    return get_logger_manager().get_hotellabpriceexport_logger()


def get_rateloader_logger() -> logging.Logger:
    """
    Get the rateloader logger (HTTP server + scheduler + queue) with [RATELOADER] prefix.

    Returns:
        Logger instance for HTTP server + scheduler + queue
    """
    return get_logger_manager().get_rateloader_logger()


def get_gui_logger() -> logging.Logger:
    """
    Get the GUI logger with [GUI] prefix.

    Returns:
        Logger instance for GUI operations
    """
    return get_logger_manager().get_gui_logger()


def get_oracle_logger() -> logging.Logger:
    """
    Get the Oracle logger with [ORACLE] prefix.

    Returns:
        Logger instance for Oracle operations
    """
    return get_logger_manager().get_oracle_logger()


def get_scheduler_logger() -> logging.Logger:
    """
    Get the scheduler logger with [SCHEDULER] prefix.

    Returns:
        Logger instance for scheduler operations
    """
    return get_logger_manager().get_scheduler_logger()


def get_http_logger() -> logging.Logger:
    """
    Get the HTTP logger with [HTTP] prefix.

    Returns:
        Logger instance for HTTP server operations
    """
    return get_logger_manager().get_http_logger()


def get_queue_logger() -> logging.Logger:
    """
    Get the queue logger with [QUEUE] prefix.

    Returns:
        Logger instance for task queue operations
    """
    return get_logger_manager().get_queue_logger()


def setup_logging(log_dir: str = "log") -> LoggerManager:
    """
    Initialize the unified logging system.

    Args:
        log_dir: Directory where log files will be stored

    Returns:
        LoggerManager instance
    """
    global _logger_manager
    _logger_manager = LoggerManager(log_dir)
    return _logger_manager


# Convenience functions for direct logging
def log_hotellabexport_info(message: str) -> None:
    """Log info message to export logger with [EXPORT] prefix."""
    get_hotellabexport_logger().info(message)


def log_hotellabexport_error(message: str) -> None:
    """Log error message to export logger with [EXPORT] prefix."""
    get_hotellabexport_logger().error(message)


def log_hotellabexport_exception(message: str, exception: Exception) -> None:
    """Log exception to export logger with [EXPORT] prefix."""
    get_logger_manager().log_exception("EXPORT", message, exception)


def log_hotellabpriceexport_info(message: str) -> None:
    """Log info message to price export logger with [PRICE] prefix."""
    get_hotellabpriceexport_logger().info(message)


def log_hotellabpriceexport_error(message: str) -> None:
    """Log error message to price export logger with [PRICE] prefix."""
    get_hotellabpriceexport_logger().error(message)


def log_hotellabpriceexport_exception(message: str, exception: Exception) -> None:
    """Log exception to price export logger with [PRICE] prefix."""
    get_logger_manager().log_exception("PRICE", message, exception)


def log_rateloader_info(message: str) -> None:
    """Log info message to rateloader logger with [RATELOADER] prefix."""
    get_rateloader_logger().info(message)


def log_rateloader_error(message: str) -> None:
    """Log error message to rateloader logger with [RATELOADER] prefix."""
    get_rateloader_logger().error(message)


def log_rateloader_exception(message: str, exception: Exception) -> None:
    """Log exception to rateloader logger with [RATELOADER] prefix."""
    get_logger_manager().log_exception("RATELOADER", message, exception)


def log_gui_info(message: str) -> None:
    """Log info message to GUI logger with [GUI] prefix."""
    get_gui_logger().info(message)


def log_gui_error(message: str) -> None:
    """Log error message to GUI logger with [GUI] prefix."""
    get_gui_logger().error(message)


def log_gui_exception(message: str, exception: Exception) -> None:
    """Log exception to GUI logger with [GUI] prefix."""
    get_logger_manager().log_exception("GUI", message, exception)


def log_oracle_info(message: str) -> None:
    """Log info message to Oracle logger with [ORACLE] prefix."""
    get_oracle_logger().info(message)


def log_oracle_error(message: str) -> None:
    """Log error message to Oracle logger with [ORACLE] prefix."""
    get_oracle_logger().error(message)


def log_oracle_exception(message: str, exception: Exception) -> None:
    """Log exception to Oracle logger with [ORACLE] prefix."""
    get_logger_manager().log_exception("ORACLE", message, exception)


def log_scheduler_info(message: str) -> None:
    """Log info message to scheduler logger with [SCHEDULER] prefix."""
    get_scheduler_logger().info(message)


def log_scheduler_error(message: str) -> None:
    """Log error message to scheduler logger with [SCHEDULER] prefix."""
    get_scheduler_logger().error(message)


def log_scheduler_exception(message: str, exception: Exception) -> None:
    """Log exception to scheduler logger with [SCHEDULER] prefix."""
    get_logger_manager().log_exception("SCHEDULER", message, exception)


def log_http_info(message: str) -> None:
    """Log info message to HTTP logger with [HTTP] prefix."""
    get_http_logger().info(message)


def log_http_error(message: str) -> None:
    """Log error message to HTTP logger with [HTTP] prefix."""
    get_http_logger().error(message)


def log_http_exception(message: str, exception: Exception) -> None:
    """Log exception to HTTP logger with [HTTP] prefix."""
    get_logger_manager().log_exception("HTTP", message, exception)


def log_queue_info(message: str) -> None:
    """Log info message to queue logger with [QUEUE] prefix."""
    get_queue_logger().info(message)


def log_queue_error(message: str) -> None:
    """Log error message to queue logger with [QUEUE] prefix."""
    get_queue_logger().error(message)


def log_queue_exception(message: str, exception: Exception) -> None:
    """Log exception to queue logger with [QUEUE] prefix."""
    get_logger_manager().log_exception("QUEUE", message, exception)
