#!D:\IDE\Anaconda3\envs\Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
 @Author: Administrator
 @FileName: ThreadPoolInterface.py
 @DateTime: 2025/6/28 12:40
 @SoftWare: PyCharm
 @Author  ：xsh
"""

from PyQt5 import Qt
from AppInterfaces.GlobalInterface import GlobalInterface
from AppInterfaces.EventInterface import EventInterface
from AppCore.AppLevelModels.EventLevel import EventLevel
from AppInterfaces.AppTimeLoop import AppTimeLoop
from AppUtils import AppUtils
import threading
import queue
import inspect
import ctypes
import traceback

class PoolUtil:
    @staticmethod
    def async_raise(tid, exctype):
        tid = ctypes.c_long(tid)
        if not inspect.isclass(exctype):
            exctype = type(exctype)
        res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
        try:
            if res == 0:
                raise ValueError("invalid thread id")
            elif res != 1:
                ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
                raise SystemError("PyThreadState_SetAsyncExc failed")
        except Exception as e:
            # 获取当前的异常信息
            exc_type, exc_obj, tb = type(e), e, e.__traceback__

            # 获取调用栈信息
            frame = tb.tb_frame
            lineno = tb.tb_lineno
            func_name = frame.f_code.co_name
            # 获取完整的异常信息
            full_traceback = traceback.format_exception(exc_type, exc_obj, tb)
            # 构建错误信息字符串
            error_info: list[str] = [f"Error: {str(e)}", f"Function: {func_name}", f"Line: {lineno}",
                                     f"Traceback:{' '.join(full_traceback)}"]
            print("\t".join(error_info))


class ThreadPoolInterface(GlobalInterface):
    DataBuffer  : queue.Queue
    condition   : threading.Condition
    is_running  : bool
    is_finish   : bool
    Mode        : int
    NextPool    : 'ThreadPoolInterface'
    is_async    : bool
    def initData(self):
        if not self.has_DataBuffer:
            self.DataBuffer        = queue.Queue           ()
        if not self.has_condition:
            self.condition    = threading.Condition   ()
        self.is_finish  = True
        self.is_running = False
        self.NextPool   = None
        self.is_async   = False



    def deleValue(self):
        if self.isValid:
            with self.condition:
                while not self.DataBuffer.empty():
                    self.DataBuffer.get()
                    self.DataBuffer.task_done()
                    AppTimeLoop.processGlobalEvents(1000)

    def waitForEmpty(self):
        # print(f'{self.__class__.__name__} Data Length: {self.DataBuffer.qsize()}')
        if self.isValid:
            while not self.DataBuffer.empty():
                AppTimeLoop.processGlobalEvents(1000)
                # Qt.QThread.msleep(200)
                # with self.condition:
                #     self.condition.notify_all()
        # AppTimeLoop.processEvents(50)



    def Start(self):
        if self.isRunning():
            return
        self.is_running = True
        self.start(Qt.QThread.HighPriority)


    def ReSet(self):
        self.Stop()
        self.deleConnect()
        self.Start()

    def Stop(self):
        self.deleValue()
        with self.condition:
            self.is_running = False
            self.condition.notify_all()
        if isinstance(self, Qt.QThread):
            self.quit()
        AppTimeLoop.processGlobalEvents(200)

        end_times: Qt.QDateTime = Qt.QDateTime.currentDateTime().addMSecs(500)
        while True:
            if self.is_finish:
                break
            if Qt.QDateTime.currentDateTime() > end_times:
                break
            if not self.isRunning():
                break
            AppTimeLoop.processGlobalEvents(200)

        try:
            if isinstance(self, Qt.QThread):
                if self.isRunning():
                    self.terminate()
            elif isinstance(self, threading.Thread):
                if self.is_running:
                    PoolUtil.async_raise(self.ident, SystemExit)
        except Exception as e:
            AppUtils.print_Exception(e)
        # if isinstance(self, Qt.QThread):
        #     print("%-20s \t线程结束\tID:%-20s" % (self.__class__.__name__, self.currentThreadId()))
        # elif isinstance(self, threading.Thread):
        #     print("%-20s \t线程结束\tID:%-20s" % (self.__class__.__name__, self.ident))


    def push(self, item: EventInterface, *args, **kwargs):
        if isinstance(item, EventInterface):
            with self.condition:
                self.DataBuffer.put(item)
                self.condition.notify_all()

    def WaitDone(self, item, *args, **kwargs):
        if isinstance(item, EventInterface):
            item.WaitDone(*args, **kwargs)

    def process(self):
        self.is_running = True
        self.is_finish = False
        while self.is_running:
            with self.condition:
                if not self.is_running:
                    break
                if self.DataBuffer.empty() and self.is_running:

                    self.condition.wait(0.05)
                    continue
                item = self.DataBuffer.get()
                try:
                    if item is not None:
                        self.WaitDone(item)
                except Exception as e:
                    AppUtils.print_Exception(e)
                self.DataBuffer.task_done()

        self.is_running = False
        self.is_finish = True
        if isinstance(self, Qt.QThread):
            print("%-20s \t线程结束\tID:%-20s\n" % (self.__class__.__name__, self.currentThreadId().__int__()))
        elif isinstance(self, threading.Thread):
            print("%-20s \t线程结束\tID:%-20s\n" % (self.__class__.__name__, self.ident))


    @property
    def isValid(self) -> bool:
        return self.has_DataBuffer and self.has_condition

    @property
    def IsRunning(self) -> bool:
        return self.is_running

    def IsEmpty(self) -> bool:
        try:
            return self.has_queueBuffe and self.DataBuffer.empty()
        except Exception as e:
            return True


    @property
    def hasNextPool(self) -> bool:
        return hasattr(self, 'NextPool') and isinstance(self.NextPool, ThreadPoolInterface)

    @property
    def has_DataBuffer(self) -> bool:
        return hasattr(self, 'DataBuffer') and isinstance(self.DataBuffer, queue.Queue)

    @property
    def has_condition(self) -> bool:
        return hasattr(self, 'condition') and isinstance(self.condition, threading.Condition)

    @property
    def has_is_running(self) -> bool:
        return hasattr(self, 'is_running') and isinstance(self.is_running, bool)

    @property
    def has_is_finish(self) -> bool:
        return hasattr(self, 'is_finish') and isinstance(self.is_finish, bool)


    @property
    def hasMode(self) -> bool:
        return hasattr(self, 'Mode') and isinstance(self.Mode, int)


    @property
    def mode(self) -> int:
        return EventLevel.OnlyDrawMode if not self.hasMode else self.Mode

    @property
    def hasAsync(self) -> bool:
        return hasattr(self, 'is_async') and isinstance(self.is_async, (bool, int))

    @property
    def isAsync(self) -> bool:
        return False if not self.hasAsync else self.is_async



