# -*- coding: utf-8 -*-
import logging
import queue
import tkinter as tk
from logging.handlers import QueueHandler, QueueListener
from tkinter.scrolledtext import ScrolledText

class TkinterLogHandler(logging.Handler):
    """
    Redirects logs to a Tkinter text widget in a thread-safe manner.
    """
    def __init__(self, text_widget: ScrolledText):
        super().__init__()
        self.text_widget = text_widget

    def emit(self, record: logging.LogRecord):
        """
        Thread-safe emit method using Tkinter's 'after' to schedule 
        updates on the main loop.
        """
        try:
            message = self.format(record)
            # Use level first letter as tag (D, I, W, E) for coloring
            tag = record.levelname[0]
            
            # Schedule the actual UI update to run on the main thread
            self.text_widget.after(0, self._safe_append, message, tag)
        except Exception:
            self.handleError(record)

    def _safe_append(self, message: str, tag: str):
        """
        Executes the widget modification. This method is always 
        called from the main thread.
        """
        self.text_widget.configure(state='normal')
        self.text_widget.insert(tk.END, message + '\n', tag)
        self.text_widget.configure(state='disabled')
        self.text_widget.yview(tk.END)

class CustomLogger:
    """
    Singleton logger manager for PyMsc.
    Handles multi-threaded logging to console, file, and Tkinter UI.
    """
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super(CustomLogger, cls).__new__(cls)
        return cls._instance

    def __init__(self, log_file: str = 'pymsc.log', use_console: bool = True):
        if hasattr(self, 'initialized'):
            return
        
        self.initialized = True
        self.log_queue = queue.Queue()
        
        # Main logger configuration
        self.logger = logging.getLogger('PyMsc')
        self.logger.setLevel(logging.DEBUG)
        
        # Standard formatter
        formatter = logging.Formatter(
            '%(asctime)s - %(levelname)s - %(message)s',
            datefmt='%y%m%d%H%M%S'
        )

        # 1. Console Handler
        if use_console:
            console_handler = logging.StreamHandler()
            console_handler.setFormatter(formatter)
            self.logger.addHandler(console_handler)

        # 2. File Handler
        file_handler = logging.FileHandler(log_file)
        file_handler.setFormatter(formatter)
        self.logger.addHandler(file_handler)
        
        self.listener = None

    def setup_tkinter_logging(self, parent_frame: tk.Frame):
        """
        Initializes the ScrolledText widget and starts the QueueListener 
        to capture logs from all threads.
        """
        # UI Component for logs
        self.scrolled_text = ScrolledText(
            parent_frame, 
            state='disabled', 
            height=5, 
            bg="black", 
            fg="white",
            font=("Consolas", 8)
        )
        self.scrolled_text.pack(padx=5, pady=5, fill=tk.BOTH, expand=True)
        
        # Define color tags matching record.levelname[0]
        self.scrolled_text.tag_configure('D', foreground='lightgray')  # Debug
        self.scrolled_text.tag_configure('I', foreground='white')      # Info
        self.scrolled_text.tag_configure('W', foreground='yellow')     # Warning
        self.scrolled_text.tag_configure('E', foreground='red')        # Error

        # Attach QueueHandler to the logger to redirect all logs to the queue
        queue_handler = QueueHandler(self.log_queue)
        self.logger.addHandler(queue_handler)
        
        # Create the custom Tkinter handler
        tk_handler = TkinterLogHandler(self.scrolled_text)
        
        # QueueListener will pull from queue and call tk_handler.emit in its thread
        self.listener = QueueListener(self.log_queue, tk_handler)
        self.listener.start()

    def get_logger(self) -> logging.Logger:
        """Returns the logger instance."""
        return self.logger

    def stop_listener(self):
        """Stops the queue listener thread safely."""
        if self.listener:
            self.listener.stop()