# -*- coding: iso-8859-1 -*-
"""
Temperature monitoring thread.

This module provides a thread that periodically reads temperature from a controller
and stores it in a TemperatureResult object.
"""

import threading
import time
import datetime

from damaris.data import TemperatureResult
from damaris.tools.temperature import TemperatureController

# GTK imports are done lazily to avoid initialization issues
_HAS_GTK = None
_gdk = None


def _get_gdk():
    """Lazily import gdk to avoid GTK initialization issues."""
    global _HAS_GTK, _gdk
    if _HAS_GTK is None:
        try:
            import gi
            gi.require_version('Gdk', '3.0')
            from gi.repository import Gdk as gdk
            _gdk = gdk
            _HAS_GTK = True
        except (ImportError, ValueError):
            _HAS_GTK = False
    return _gdk if _HAS_GTK else None


class TemperatureMonitor(threading.Thread):
    """
    Thread that periodically reads temperature from a controller
    and stores it in a TemperatureResult object.
    
    This thread runs independently and can be configured with any
    TemperatureController implementation (Eurotherm, Lakeshore, etc.).
    
    Attributes:
        controller: The TemperatureController instance to read from.
        interval: Polling interval in seconds.
        result: The TemperatureResult object storing collected data.
        quit_flag: Event to signal the thread to stop.
        data_pool: Optional DataPool to store results.
        data_key: Key to use when storing in data_pool.
    """

    def __init__(self, controller: TemperatureController,
                 interval: float = 1.0,
                 data_pool=None,
                 data_key: str = "temperature"):
        """
        Initialize the temperature monitor.
        
        Args:
            controller: TemperatureController implementation (Eurotherm, etc.)
            interval: Polling interval in seconds (default: 1.0)
            data_pool: Optional DataPool to store results (default: None)
            data_key: Key to use when storing in data_pool (default: "temperature")
        """
        threading.Thread.__init__(self, name="TemperatureMonitor")
        self.controller = controller
        self.interval = float(interval)
        self.data_pool = data_pool
        self.data_key = data_key
        self.quit_flag = threading.Event()
        self.result = TemperatureResult()
        self._running = False
        self._lock = threading.RLock()
        
        # Initialize the result with metadata
        self.result.xlabel = "Time (s)"
        self.result.ylabel = "Temperature (C)"
        self.result.description = {"type": "temperature_monitoring"}

    def run(self):
        """
        Main thread loop: periodically reads temperature and stores it.
        """
        self._running = True
        start_time = time.time()
        
        while not self.quit_flag.is_set() and self._running:
            try:
                # Read temperature and setpoint
                timestamp = time.time() - start_time
                current_temp = self.controller.get_temperature()
                setpoint = self.controller.get_setpoint()
                
                # Store in result
                with self._lock:
                    if not hasattr(self.result, 'x'):
                        self.result.x = []
                        self.result.y = []
                        self.result.setpoint = []
                    
                    self.result.x.append(timestamp)
                    self.result.y.append(current_temp)
                    self.result.setpoint.append(setpoint)
                    
                    # Update job metadata on first sample
                    if len(self.result.x) == 1:
                        self.result.job_date = datetime.datetime.now()
                        self.result.job_id = id(self)
                
                # Store result in data_pool (thread-safe for GTK)
                # Replace the entry on each update to trigger DataPool events
                if self.data_pool is not None:
                    with self._lock:
                        # Create a copy for the data_pool with current data
                        data_pool_result = TemperatureResult()
                        data_pool_result.xlabel = self.result.xlabel
                        data_pool_result.ylabel = self.result.ylabel
                        data_pool_result.description = self.result.description.copy() if isinstance(self.result.description, dict) else {}
                        # Copy the data from self.result
                        data_pool_result.x = list(self.result.x) if hasattr(self.result, 'x') else []
                        data_pool_result.y = list(self.result.y) if hasattr(self.result, 'y') else []
                        data_pool_result.setpoint = list(self.result.setpoint) if hasattr(self.result, 'setpoint') else []
                        data_pool_result.job_id = self.result.job_id if hasattr(self.result, 'job_id') else None
                        data_pool_result.job_date = self.result.job_date if hasattr(self.result, 'job_date') else None
                    
                    # Store in data_pool in GTK thread (if GTK available)
                    gdk = _get_gdk()
                    if gdk is not None:
                        gdk.threads_enter()
                        try:
                            self.data_pool[self.data_key] = data_pool_result
                        finally:
                            gdk.threads_leave()
                    else:
                        self.data_pool[self.data_key] = data_pool_result
                
            except Exception as e:
                print(f"TemperatureMonitor error: {e}")
                import traceback
                traceback.print_exc()
            
            # Sleep in small increments for responsive shutdown
            sleep_remaining = self.interval
            while sleep_remaining > 0 and not self.quit_flag.is_set() and self._running:
                sleep_time = min(0.1, sleep_remaining)
                self.quit_flag.wait(sleep_time)
                sleep_remaining -= sleep_time

    def stop(self):
        """
        Graceful shutdown: signal the thread to stop and wait for it.
        """
        self._running = False
        self.quit_flag.set()
        # Wait for the thread to finish, with a generous timeout
        # Use a longer timeout to account for potential delays
        if self.is_alive():
            self.join(timeout=5.0)  # Wait up to 5 seconds
            if self.is_alive():
                print("Warning: TemperatureMonitor thread did not stop gracefully")
                # Thread is still running, but we can't force stop it
                # The next start will check if it's alive and handle it

    def reset(self):
        """
        Clear the collected data and start fresh.
        """
        with self._lock:
            self.result = TemperatureResult()
            self.result.xlabel = "Time (s)"
            self.result.ylabel = "Temperature (C)"
            self.result.description = {"type": "temperature_monitoring"}

    def get_current_temperature(self) -> float:
        """
        Get the latest temperature reading.
        
        Returns:
            float: Latest temperature in Celsius, or 0.0 if no data.
        """
        with self._lock:
            if hasattr(self.result, 'y') and len(self.result.y) > 0:
                return self.result.y[-1]
            return 0.0

    def get_current_setpoint(self) -> float:
        """
        Get the latest setpoint reading.
        
        Returns:
            float: Latest setpoint in Celsius, or 0.0 if no data.
        """
        with self._lock:
            if hasattr(self.result, 'setpoint') and len(self.result.setpoint) > 0:
                return self.result.setpoint[-1]
            return 0.0

    def is_running(self) -> bool:
        """
        Check if the monitor is currently running.
        
        Returns:
            bool: True if the monitor thread is active.
        """
        return self._running and not self.quit_flag.is_set()
