# scenario_simulator/utils/logger.py
import logging
import logging.handlers  # For RotatingFileHandler
import tkinter as tk
from tkinter.scrolledtext import ScrolledText
from queue import Queue, Empty as QueueEmpty
from typing import Optional, Dict, Any

# --- Module-level globals for the centralized logging queue system ---
_global_log_queue: Optional[Queue[logging.LogRecord]] = None
_actual_console_handler: Optional[logging.StreamHandler] = None
_actual_file_handler: Optional[logging.handlers.RotatingFileHandler] = None
_actual_tkinter_handler: Optional["TkinterTextHandler"] = None

_log_processor_after_id: Optional[str] = None
_logging_system_active: bool = False
_tk_root_instance_for_processing: Optional[tk.Tk] = None
_base_formatter: Optional[logging.Formatter] = None

GLOBAL_LOG_QUEUE_POLL_INTERVAL_MS = 100


class TkinterTextHandler(logging.Handler):
    """
    A logging handler that directs log messages to a Tkinter Text widget.
    This handler is called directly from the GUI thread's processing loop.
    """

    def __init__(self, text_widget: tk.Text, level_colors: Dict[int, str]):
        super().__init__()
        self.text_widget = text_widget
        self.level_colors = level_colors
        self._configure_tags()

    def _configure_tags(self):
        for level, color_value in self.level_colors.items():
            level_name = logging.getLevelName(level)
            if color_value:
                try:
                    self.text_widget.tag_config(level_name, foreground=color_value)
                except tk.TclError:
                    pass  # Widget might not be ready

    def emit(self, record: logging.LogRecord):
        try:
            if not self.text_widget.winfo_exists():
                return

            msg = self.format(record)
            level_name = record.levelname

            self.text_widget.configure(state=tk.NORMAL)
            self.text_widget.insert(tk.END, msg + "\n", (level_name,))
            self.text_widget.configure(state=tk.DISABLED)
            self.text_widget.see(tk.END)
        except Exception as e:
            print(f"Error in TkinterTextHandler.emit: {e}", flush=True)


class QueuePuttingHandler(logging.Handler):
    """
    A simple handler that puts any received LogRecord into a global queue.
    """

    def __init__(self, handler_queue: Queue[logging.LogRecord]):
        super().__init__()
        self.handler_queue = handler_queue

    def emit(self, record: logging.LogRecord):
        self.handler_queue.put_nowait(record)


def _process_global_log_queue():
    """
    GUI Thread: Periodically processes LogRecords from the _global_log_queue
    and dispatches them to the actual configured handlers.
    """
    global _logging_system_active, _log_processor_after_id

    if (
        not _logging_system_active
        or not _tk_root_instance_for_processing
        or not _tk_root_instance_for_processing.winfo_exists()
    ):
        return

    try:
        while _global_log_queue and not _global_log_queue.empty():
            record = _global_log_queue.get_nowait()
            if _actual_console_handler:
                _actual_console_handler.handle(record)
            if _actual_file_handler:
                _actual_file_handler.handle(record)
            if _actual_tkinter_handler:
                _actual_tkinter_handler.handle(record)
            _global_log_queue.task_done()
    except QueueEmpty:
        pass
    except Exception as e:
        print(f"Error in log processing queue: {e}", flush=True)
    finally:
        if _logging_system_active:
            _log_processor_after_id = _tk_root_instance_for_processing.after(
                GLOBAL_LOG_QUEUE_POLL_INTERVAL_MS, _process_global_log_queue
            )


def setup_basic_logging(
    root_tk_instance_for_processor: tk.Tk,
    logging_config_dict: Optional[Dict[str, Any]] = None,
):
    global _global_log_queue, _actual_console_handler, _actual_file_handler, _logging_system_active
    global _tk_root_instance_for_processing, _log_processor_after_id, _base_formatter

    if _logging_system_active:
        return

    if logging_config_dict is None:
        logging_config_dict = {}

    log_format_str = logging_config_dict.get(
        "format", "% (asctime)s [%(levelname)-8s] %(name)-25s : %(message)s"
    )
    log_date_format_str = logging_config_dict.get("date_format", "%Y-%m-%d %H:%M:%S")
    _base_formatter = logging.Formatter(log_format_str, datefmt=log_date_format_str)

    _global_log_queue = Queue()
    _tk_root_instance_for_processing = root_tk_instance_for_processor

    root_logger = logging.getLogger()
    for handler in root_logger.handlers[:]:
        root_logger.removeHandler(handler)
    root_logger.setLevel(logging_config_dict.get("default_root_level", logging.INFO))

    if logging_config_dict.get("enable_console", True):
        _actual_console_handler = logging.StreamHandler()
        _actual_console_handler.setFormatter(_base_formatter)
        _actual_console_handler.setLevel(logging.DEBUG)

    queue_putter = QueuePuttingHandler(handler_queue=_global_log_queue)
    queue_putter.setLevel(logging.DEBUG)
    root_logger.addHandler(queue_putter)

    _logging_system_active = True
    _log_processor_after_id = _tk_root_instance_for_processing.after(
        GLOBAL_LOG_QUEUE_POLL_INTERVAL_MS, _process_global_log_queue
    )


def add_tkinter_handler(gui_log_widget: tk.Text, logging_config_dict: Dict[str, Any]):
    global _actual_tkinter_handler, _base_formatter

    if not _logging_system_active or not _base_formatter:
        return

    if _actual_tkinter_handler:
        _actual_tkinter_handler.close()

    if (
        isinstance(gui_log_widget, (tk.Text, ScrolledText))
        and gui_log_widget.winfo_exists()
    ):
        level_colors = logging_config_dict.get("colors", {})
        _actual_tkinter_handler = TkinterTextHandler(
            text_widget=gui_log_widget, level_colors=level_colors
        )
        _actual_tkinter_handler.setFormatter(_base_formatter)
        _actual_tkinter_handler.setLevel(logging.DEBUG)
        logging.getLogger(__name__).info("Tkinter log handler added successfully.")
    else:
        print(
            "ERROR: GUI log widget invalid, cannot add TkinterTextHandler.", flush=True
        )


def get_logger(name: str) -> logging.Logger:
    return logging.getLogger(name)


def shutdown_logging_system():
    global _logging_system_active, _log_processor_after_id
    if not _logging_system_active:
        return
    _logging_system_active = False
    if (
        _log_processor_after_id
        and _tk_root_instance_for_processing
        and _tk_root_instance_for_processing.winfo_exists()
    ):
        _tk_root_instance_for_processing.after_cancel(_log_processor_after_id)
    # Final flush of the queue
    _process_global_log_queue()
    logging.shutdown()
