"""Scan Worker module for core."""

from __future__ import annotations

import logging
from contextlib import suppress

from PySide2.QtCore import QObject, QThread, Signal

from pytola_office.docscan.cli import DocumentScanner


class ScanWorker(QThread):
    """Worker thread for running document scan in background."""

    def __init__(self, scanner: DocumentScanner, threads: int) -> None:
        """Initialize worker thread."""
        super().__init__()
        self.scanner = scanner
        self.threads = threads
        self.signals = WorkerSignals()

    def _create_progress_handler(self) -> logging.Handler:
        """Create a logging handler that emits progress messages."""

        class ProgressHandler(logging.Handler):
            def __init__(self, signal: Signal[str]) -> None:
                super().__init__()
                self.signal = signal

            def emit(self, record: logging.LogRecord) -> None:
                # Format the message and send it via signal
                with suppress(ValueError, TypeError, AttributeError):
                    message = self.format(record)
                    # Only emit non-empty messages
                    if message and message.strip():
                        self.signal.emit(message)

        handler = ProgressHandler(self.signals.progress_message)
        handler.setFormatter(logging.Formatter("%(message)s"))
        return handler

    def _setup_loggers(self, handler: logging.Handler) -> dict:
        """Set up loggers to capture progress messages.

        Returns
        -------
            Dictionary mapping loggers to their original handlers.
        """
        loggers_to_monitor = [
            logging.getLogger(__name__),  # Main GUI logger
            logging.getLogger("docscan"),  # DocScan module logger
            logging.getLogger("pytola.docscan"),  # Full module path logger
            logging.getLogger(),  # Root logger
            logging.getLogger("docscan.docscan"),  # Direct module logger
        ]

        # Store original handlers for cleanup
        original_handlers = {}
        for logger in loggers_to_monitor:
            original_handlers[logger] = list(logger.handlers)
            logger.addHandler(handler)
            logger.setLevel(logging.INFO)

        return original_handlers

    def _cleanup_loggers(self, loggers_to_monitor: list, handler: logging.Handler, original_handlers: dict) -> None:
        """Clean up custom logging handlers and restore originals."""
        for logger in loggers_to_monitor:
            if logger in original_handlers:
                # Remove our handler while preserving original ones
                with suppress(ValueError, TypeError):
                    # Handler might have already been removed
                    logger.removeHandler(handler)
                # Restore original handlers
                logger.handlers = original_handlers[logger]

    def _get_loggers_to_monitor(self) -> list:
        """Get list of loggers to monitor for progress messages."""
        return [
            logging.getLogger(__name__),
            logging.getLogger("docscan"),
            logging.getLogger("pytola.docscan"),
            logging.getLogger(),
            logging.getLogger("docscan.docscan"),
        ]

    def run(self) -> None:
        """Run the document scan."""
        try:
            # Set up custom logger to capture messages from all relevant loggers
            handler = self._create_progress_handler()

            # Add handler to multiple loggers to catch all messages
            original_handlers = self._setup_loggers(handler)

            # Set progress callback
            def progress_callback(current: int, total: int) -> None:
                self.signals.progress_update.emit(current, total)

            self.scanner.set_progress_callback(progress_callback)
            self.signals.progress_message.emit("开始扫描...")

            # Perform the scan
            results = self.scanner.scan(threads=self.threads, show_progress=True)

            # Clean up handlers
            self._cleanup_loggers(self._get_loggers_to_monitor(), handler, original_handlers)

            self.signals.progress_message.emit("扫描完成!")
            self.signals.scan_finished.emit(results)
        except RuntimeError as e:
            # Ensure handler is removed even if error occurs
            try:
                for logger in self._get_loggers_to_monitor():
                    with suppress(ValueError, TypeError):
                        # Handler might have already been removed or invalid
                        logger.removeHandler(handler)
            except (OSError, AttributeError):
                # Logger cleanup failed, but continue with error reporting
                pass
            self.signals.scan_error.emit(str(e))


class WorkerSignals(QObject):
    """Defines the signals available from a running worker thread."""

    # Progress reporting signals
    progress_message = Signal(str)
    progress_update = Signal(int, int)

    # Completion signals
    scan_finished = Signal(dict)
    scan_error = Signal(str)
