import os, time, queue, numpy as np, importlib.util
from PyQt5.QtCore import QThread, pyqtSignal
from src.config import UTILS_DIR

def load_inference_module(mode, model_name):
    """Dynamically load an inference module"""
    script_path = os.path.join(UTILS_DIR, mode, model_name, "script.py")
    module_name = f"{mode}_{model_name}"
    spec = importlib.util.spec_from_file_location(module_name, script_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

class InferenceWorkerThread(QThread):
    inference_result_signal = pyqtSignal(object)

    def __init__(self, frame_queue, mode, model_name, min_interval=0.5, mse_threshold=500, once_mode=False):
        super().__init__()
        self.frame_queue = frame_queue
        self.mode = mode
        self.model_name = model_name
        self.min_interval = min_interval
        self.mse_threshold = mse_threshold
        self._running = True
        self.once_mode = once_mode
        self.last_inference_time = 0
        self.last_frame = None
        self.cached_result = None
        self.input_params = {}
        
        # Dynamically load inference module
        self.inference_module = load_inference_module(mode, model_name)

    def run(self):
        while self._running:
            try:
                frame = self.frame_queue.get(timeout=0.1)
            except queue.Empty:
                continue

            current_time = time.time()
            if current_time - self.last_inference_time < self.min_interval:
                continue

            if self.last_frame is not None:
                # 檢查當前幀與上一幀的尺寸是否相同
                if frame.shape != self.last_frame.shape:
                    print(f"幀尺寸變更: 從 {self.last_frame.shape} 變更為 {frame.shape}")
                    # 尺寸不同時，重置上一幀和緩存結果
                    self.last_frame = None
                    self.cached_result = None
                else:
                    # 只有在尺寸相同時才進行 MSE 計算
                    try:
                        mse = np.mean((frame.astype(np.float32) - self.last_frame.astype(np.float32)) ** 2)
                        if mse < self.mse_threshold and self.cached_result is not None:
                            self.inference_result_signal.emit(self.cached_result)
                            if self.once_mode:
                                self._running = False
                                break
                            continue
                    except Exception as e:
                        print(f"計算 MSE 時發生錯誤: {e}")
                        # 發生錯誤時重置上一幀和緩存結果
                        self.last_frame = None
                        self.cached_result = None

            try:
                result = self.inference_module.inference(frame, params=self.input_params)
            except Exception as e:
                print(f"Inference error: {e}")
                result = None

            self.last_inference_time = current_time
            self.last_frame = frame.copy()
            self.cached_result = result
            self.inference_result_signal.emit(result)

            if self.once_mode:
                self._running = False
                break

        self.quit()

    def stop(self):
        self._running = False
        self.wait()