#!/usr/bin/env python3
"""
Shutdown Detection Utility for Workstatus
Detects when the app is terminated from Task Manager or other methods.
"""

import signal
import atexit
import threading
import time
import os
import sys
import platform
import psutil
from pathlib import Path
from ws_package.log.writer import LogWriter

logger = LogWriter.file(__name__)

class ShutdownDetector:
    """
    Comprehensive shutdown detection for Workstatus app.
    Detects termination from Task Manager, Ctrl+C, system shutdown, etc.
    """
    
    def __init__(self, app_name="Workstatus"):
        self.app_name = app_name
        self.current_pid = os.getpid()
        self.shutdown_detected = False
        self.shutdown_reason = "Unknown"
        self.monitor_thread = None
        self.stop_monitoring = threading.Event()
        
        # Register cleanup handlers
        self._register_signal_handlers()
        self._register_console_ctrl_handler()
        self._register_atexit_handlers()
        
        # Start monitoring thread
        self._start_monitoring()
        
        logger.info("[SHUTDOWN_DETECTOR] Initialized for PID %s", self.current_pid)
    
    def _register_signal_handlers(self):
        """Register signal handlers for graceful shutdown detection."""
        try:
            # SIGTERM - Normal termination request
            signal.signal(signal.SIGTERM, self._signal_handler)
            logger.info("[SHUTDOWN_DETECTOR] Registered SIGTERM handler")
        except (OSError, ValueError) as e:
            logger.warning("[SHUTDOWN_DETECTOR] Could not register SIGTERM: %s", e)
        
        try:
            # SIGINT - Ctrl+C
            signal.signal(signal.SIGINT, self._signal_handler)
            logger.info("[SHUTDOWN_DETECTOR] Registered SIGINT handler")
        except (OSError, ValueError) as e:
            logger.warning("[SHUTDOWN_DETECTOR] Could not register SIGINT: %s", e)
        
        if platform.system() == "Windows":
            try:
                # Windows-specific signals
                signal.signal(signal.SIGBREAK, self._signal_handler)
                logger.info("[SHUTDOWN_DETECTOR] Registered SIGBREAK handler")
            except (OSError, ValueError) as e:
                logger.warning("[SHUTDOWN_DETECTOR] Could not register SIGBREAK: %s", e)

    def _register_console_ctrl_handler(self):
        """Register Windows Console Control handler to catch console close/logoff/shutdown."""
        if platform.system() != "Windows":
            return
        try:
            import win32api
            import win32con
        except Exception as e:
            logger.warning("[SHUTDOWN_DETECTOR] pywin32 not available for console handler: %s", e)
            return

        ctrl_names = {
            getattr(win32con, "CTRL_C_EVENT", 0): "CTRL_C_EVENT",
            getattr(win32con, "CTRL_BREAK_EVENT", 1): "CTRL_BREAK_EVENT",
            getattr(win32con, "CTRL_CLOSE_EVENT", 2): "CTRL_CLOSE_EVENT",
            getattr(win32con, "CTRL_LOGOFF_EVENT", 5): "CTRL_LOGOFF_EVENT",
            getattr(win32con, "CTRL_SHUTDOWN_EVENT", 6): "CTRL_SHUTDOWN_EVENT",
        }

        def handler(ctrl_type):
            name = ctrl_names.get(ctrl_type, str(ctrl_type))
            self.shutdown_reason = f"Console control: {name}"
            logger.info("[SHUTDOWN_DETECTOR][CONSOLE_CTRL] Received: %s", name)
            # Synchronously log detailed shutdown info
            self._log_shutdown_event()
            # Return True to indicate the event was handled; process will still close for CLOSE/LOGOFF/SHUTDOWN
            return True

        try:
            win32api.SetConsoleCtrlHandler(handler, True)
            logger.info("[SHUTDOWN_DETECTOR] Windows Console Control handler registered")
        except Exception as e:
            logger.warning("[SHUTDOWN_DETECTOR] Failed to register console handler: %s", e)
    
    def _register_atexit_handlers(self):
        """Register atexit handlers for cleanup."""
        atexit.register(self._atexit_handler)
        logger.info("[SHUTDOWN_DETECTOR] Registered atexit handler")
    
    def _signal_handler(self, signum, frame):
        """Handle termination signals with bounded execution time.

        Win11 enforces stricter process termination deadlines than Win10.
        All critical state is flushed immediately; cleanup is given at most
        3 seconds before we allow the process to exit naturally.
        """
        signal_name = signal.Signals(signum).name
        self.shutdown_reason = f"Signal {signal_name} ({signum})"
        # Log immediately — don't defer; Win11 may kill us before a thread wakes.
        logger.info("[SHUTDOWN_DETECTOR] Received signal: %s", signal_name)
        self._log_shutdown_event()
        # Synchronously flush all log handlers before spawning the cleanup thread.
        # On Win11 the OS can terminate the process before daemon threads run.
        import logging as _logging
        for _h in _logging.root.handlers:
            try:
                _h.flush()
            except Exception:
                pass
        # Run cleanup on a daemon thread so we don't block beyond the timeout.
        cleanup_done = threading.Event()

        def _bounded_cleanup():
            try:
                self._cleanup()
            finally:
                cleanup_done.set()

        t = threading.Thread(target=_bounded_cleanup, daemon=True)
        t.start()
        cleanup_done.wait(timeout=3.0)  # give cleanup at most 3 s then let process exit
    
    def _atexit_handler(self):
        """Handle normal program exit."""
        if not self.shutdown_detected:
            self.shutdown_reason = "Normal exit (atexit)"
            logger.info("[SHUTDOWN_DETECTOR] Normal program exit detected")
            self._log_shutdown_event()
    
    def _start_monitoring(self):
        """Start background monitoring thread."""
        self.monitor_thread = threading.Thread(
            target=self._monitor_process,
            name="ShutdownMonitor",
            daemon=True
        )
        self.monitor_thread.start()
        logger.info("[SHUTDOWN_DETECTOR] Started background monitoring thread")
    
    def _monitor_process(self):
        """Monitor process status in background thread."""
        try:
            current_process = psutil.Process(self.current_pid)
            logger.info("[SHUTDOWN_DETECTOR] Monitoring process: %s (PID: %s)", current_process.name(), self.current_pid)
            
            while not self.stop_monitoring.is_set():
                try:
                    # Check if process still exists
                    if not current_process.is_running():
                        self.shutdown_reason = "Process terminated externally"
                        logger.info("[SHUTDOWN_DETECTOR] Process no longer running")
                        self._log_shutdown_event()
                        break
                    
                    # Check for parent process termination (useful when console host is killed)
                    try:
                        parent = current_process.parent()
                        if parent and not parent.is_running():
                            self.shutdown_reason = "Parent process terminated"
                            logger.info("[SHUTDOWN_DETECTOR] Parent process terminated")
                            self._log_shutdown_event()
                            break
                    except (psutil.NoSuchProcess, psutil.AccessDenied):
                        pass
                    
                    time.sleep(1)  # Check every second
                    
                except (psutil.NoSuchProcess, psutil.AccessDenied) as e:
                    self.shutdown_reason = f"Process monitoring failed: {e}"
                    logger.warning("[SHUTDOWN_DETECTOR] Process monitoring error: %s", e)
                    break
                    
        except Exception as e:
            logger.error("[SHUTDOWN_DETECTOR] Monitoring thread error: %s", e)
    
    def _log_shutdown_event(self):
        """Log detailed shutdown information."""
        if self.shutdown_detected:
            return  # Already logged
        
        self.shutdown_detected = True
        
        try:
            # Get process info
            current_process = psutil.Process(self.current_pid)
            process_info = {
                "pid": self.current_pid,
                "name": current_process.name(),
                "cmdline": " ".join(current_process.cmdline()),
                "create_time": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(current_process.create_time())),
                "cpu_percent": current_process.cpu_percent(),
                "memory_info": dict(current_process.memory_info()._asdict()),
                "status": current_process.status(),
                "username": current_process.username(),
                "working_dir": current_process.cwd()
            }
            
            # Get system info
            system_info = {
                "platform": platform.system(),
                "platform_version": platform.version(),
                "machine": platform.machine(),
                "processor": platform.processor(),
                "python_version": sys.version,
                "frozen": getattr(sys, 'frozen', False),
                "executable": sys.executable
            }
            
            # Log the shutdown event
            logger.info("=" * 80)
            logger.info("🚨 WORKSTATUS APP SHUTDOWN DETECTED 🚨")
            logger.info("=" * 80)
            logger.info("Shutdown Reason: %s", self.shutdown_reason)
            logger.info("Timestamp: %s", time.strftime('%Y-%m-%d %H:%M:%S'))
            logger.info("App Name: %s", self.app_name)
            logger.info("-" * 40)
            logger.info("PROCESS INFORMATION:")
            for key, value in process_info.items():
                logger.info("  %s: %s", key, value)
            logger.info("-" * 40)
            logger.info("SYSTEM INFORMATION:")
            for key, value in system_info.items():
                logger.info("  %s: %s", key, value)
            logger.info("-" * 40)
            
            # Additional Windows-specific info
            if platform.system() == "Windows":
                try:
                    import win32api
                    import win32process
                    import win32con
                    handle = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION, False, self.current_pid)
                    exit_code = win32process.GetExitCodeProcess(handle)
                    win32api.CloseHandle(handle)
                    if exit_code != win32con.STILL_ACTIVE:
                        logger.info("Windows Exit Code: %s", exit_code)
                except Exception as e:
                    logger.warning("Could not get Windows exit code: %s", e)
            
            logger.info("=" * 80)
            
        except Exception as e:
            logger.error("[SHUTDOWN_DETECTOR] Error logging shutdown event: %s", e)
    
    def _cleanup(self):
        """Perform cleanup operations."""
        try:
            logger.info("[SHUTDOWN_DETECTOR] Performing cleanup...")
            
            # Stop monitoring thread
            if self.monitor_thread and self.monitor_thread.is_alive():
                self.stop_monitoring.set()
                self.monitor_thread.join(timeout=2)
                logger.info("[SHUTDOWN_DETECTOR] Monitoring thread stopped")
            
            logger.info("[SHUTDOWN_DETECTOR] Cleanup completed")
            
        except Exception as e:
            logger.error("[SHUTDOWN_DETECTOR] Error during cleanup: %s", e)
    
    def is_shutdown_detected(self):
        """Check if shutdown has been detected."""
        return self.shutdown_detected
    
    def get_shutdown_reason(self):
        """Get the reason for shutdown."""
        return self.shutdown_reason
    
    def stop(self):
        """Manually stop the shutdown detector."""
        logger.info("[SHUTDOWN_DETECTOR] Manually stopping shutdown detector")
        self._cleanup()

# Global instance
_shutdown_detector = None

def init_shutdown_detector(app_name="Workstatus"):
    """Initialize the global shutdown detector."""
    global _shutdown_detector
    if _shutdown_detector is None:
        _shutdown_detector = ShutdownDetector(app_name)
    return _shutdown_detector

def get_shutdown_detector():
    """Get the global shutdown detector instance."""
    return _shutdown_detector

def is_shutdown_detected():
    """Check if shutdown has been detected."""
    if _shutdown_detector:
        return _shutdown_detector.is_shutdown_detected()
    return False

def get_shutdown_reason():
    """Get the reason for shutdown."""
    if _shutdown_detector:
        return _shutdown_detector.get_shutdown_reason()
    return "Shutdown detector not initialized"
