#!D:\IDE\Anaconda3\envs\Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
@FileName   : ProcessCellFocusingPool.py
@Account    : Administrator
@Time       : 2025/10/23 18:01
@Author     : xsh
@Description: 
"""
import threading
import cv2
import numpy as np
import math
import time
import os
import cv2
from PyQt5 import Qt
from datetime import datetime, date
from AppInterfaces.ThreadPoolInterface                      import ThreadPoolInterface, PoolUtil    #
from AppBackEnd.BackEndEventBus.DataOnlyDrawPool            import DataOnlyDrawPool
from AppBackEnd.BackEndEventBus.DataWebSocketPool           import DataWebSocketPool
from AppInterfaces.EventInterface                           import EventInterface
from AppInterfaces.utils                                    import *
from AppCore.DBModels                                       import *
from AppCore.Levels                                         import *
from AppCore.Requests                                       import *
from AppCore.Events                                         import *
from AppCore.Readers                                        import WebReader, AppWebSocket
from AppCore.Impls                                          import WebSocketServer, WebSocketClient
from AppUtils.utils                                         import *
from AppSettings.utils                                      import *
from AppSettings.AppGlobalStatus                            import AppGlobalStatus, AppStatus
from AppCore.AppEvents.ImageEventInterface                  import ImageEventInterface
from AppCore.AppManagers.ProcessManager                     import ImageSaveProcess, SaveSlide, TextSaveProcess
from AppBackEnd.BackEndEventBus.SlideFocusingPool           import SlideFocusingPool
from AppUtils.AppDBUtils                                    import AppDBUtils
from AppCore.AppAlgorithms.ImageAlgorithm                   import ImageAlgorithm
class ProcessCellFocusingPool(Qt.QThread, ThreadPoolInterface, SingletonInterface):
    AppendItem          : Qt.pyqtSignal = Qt.pyqtSignal(object)
    _IOLocker           : Qt.QReadWriteLock = Qt.QReadWriteLock()
    OnlyDrawPool        : DataOnlyDrawPool          # 图像显示线程
    WebSocketPool       : DataWebSocketPool         # 网络发送线程

    @classmethod
    def GetInstance(cls, *args, **kwargs) -> 'ProcessCellFocusingPool':
        return super(ProcessCellFocusingPool, cls).GetInstance(*args, **kwargs)

    def __init__(self, parent: Qt.QObject = None):
        super(ProcessCellFocusingPool, self).__init__(parent=parent)
        self.Initialization('ProcessCellFocusingPool', self, parent)
        self.Mode = EventLevel.QualityMode
        self.isShowFocusing = True
        self.Start()


    def initConnect(self):
        super(ProcessCellFocusingPool, self).initConnect()
        TYPE: Qt.Qt.ConnectionType = Qt.Qt.ConnectionType(Qt.Qt.QueuedConnection | Qt.Qt.UniqueConnection)
        self.AppendItem.connect(slot=self.slot_AppendItem, type=TYPE)

    def StartFocusing(self, isShowFocusing: bool = True):
        self.initPools          ()
        self.initFocusModels    ()
        self.isShowFocusing     = isShowFocusing
        self.Start              ()

    def StopFocusing(self, isShowFocusing: bool = True):
        self.initFocusModels()
        self.isShowFocusing = isShowFocusing

    def deleConnect(self):
        super(ProcessCellFocusingPool, self).deleConnect()
    #
    def slot_AppendItem(self, item):
        self.appendItem(item)

    def appendItem(self, item: HigObjectiveCellModel, *args, **kwargs):
        if not self.isRunning():
            self.is_running = True
            self.start(Qt.QThread.HighPriority)
        if isinstance(item, HigObjectiveCellModel):
            with self.condition:
                self.DataBuffer.put(item)
                self.condition.notify_all()

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

    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)
        self.delePools()



    def deleValue(self):
        super(ProcessCellFocusingPool, self).deleValue()
        if self.isValid:
            with self.condition:
                while not self.DataBuffer.empty():
                    self.DataBuffer.get()
                    self.DataBuffer.task_done()
                    Qt.QApplication.processEvents(1000)
    def run(self) -> None:
        if not self.isAvailable:
            self.initPools()
        self.process()


    def WaitDone(self, item: HigObjectiveCellModel, *args, **kwargs):
        """发送图像到界面 融合图像 保存图像 """
        if not isinstance(item, HigObjectiveCellModel) or not item.isAvailable:
            return
        """发送图像到界面"""
        imageParameter: ImageAnalysisModel = ImageAnalysisModel.getConfig(item.Classifier)
        if not isinstance(imageParameter, ImageAnalysisModel):
            return
        isGaussi: int = imageParameter.isGaussi
        AnalysisIntegrationImages: list[np.ndarray] = self.SendCellsToHeadEndAndSaveCell(item.CaseID, item.Cell, item.ExposureTimes, item.IntegrationImages, imageParameter)
        """融合图像"""
        if not isinstance(AnalysisIntegrationImages, list) or len(AnalysisIntegrationImages) <= 0:
            return

        if imageParameter.hasIntegration and imageParameter.isIntegration:
            image = ImageAlgorithm.ProcessIntegrationImages(images=AnalysisIntegrationImages, parm=imageParameter, isGaussi=isGaussi)
        elif imageParameter.hasFocusingHDR and imageParameter.isFocusingHDR:
            image = ImageAlgorithm.ProcessIntegrationImages(images=AnalysisIntegrationImages, parm=imageParameter, isGaussi=isGaussi)
        elif imageParameter.hasCameraHDR and imageParameter.isCameraHDR:
            image = ImageAlgorithm.ProcessIntegrationImages(images=AnalysisIntegrationImages, parm=imageParameter, isGaussi=isGaussi)
        else:
            image = AnalysisIntegrationImages[0]
        if not isinstance(image, np.ndarray):
            return
        drawImage: np.ndarray = ImageAlgorithm.processImage(im=image, parm=imageParameter, flag=False)

        if imageParameter.hasBigAnalysis and imageParameter.isBigAnalysis:
            image = drawImage.copy()
        """发送图像到界面"""
        self.SendCellToHeadEnd(item.CaseID, image.copy())
        """保存图像"""
        self.SaveCellModel(item.Cell, item.CaseID, image, True)



        pass

    def SendCellsToHeadEndAndSaveCell(self, CaseID: int, item: SlideModelInterface, exposureTimes: list[int], images: list[np.ndarray], imageParameter: ImageAnalysisModel) -> list[np.ndarray]:
        slide               : CellModel
        index               : int
        image               : np.ndarray
        status              : int = ScanStatusLevel.Low_Four_Focus_Status
        draw_image          : np.ndarray
        AnalysisIntegrationImages: list[np.ndarray] = []
        try:
            for index, image in enumerate(images):
                slide = item.copy()
                slide.Level = status
                slide.Index = index + 1
                slide.ImageScore = exposureTimes[index]
                slide.FocusingSavePath = self.getCellSavePath(CaseID, slide)
                if imageParameter is not None:
                    """如果小图优化"""
                    if imageParameter.isAnalysis:
                        draw_image = ImageAlgorithm.processImage(image.copy(), imageParameter)
                    else:
                        draw_image = image.copy()
                else:
                    draw_image = image.copy()
                AnalysisIntegrationImages.append(draw_image)
                """保存图像"""
                if slide.has_FocusingSavePath:
                    try:
                        if slide.hasPreview and slide.preview.is_save:
                            ImageSaveProcess(filename, draw_image.copy())
                        elif SystemConfig.isDebugMode():
                            ImageSaveProcess(filename, draw_image.copy())
                    except Exception as focusing_ex:
                        AppUtils.print_Exception(focusing_ex)
                self.webSocket.AppendItem.emit(Response.VideoStream(draw_image.copy()))
                if HeadEndShowMode.get('DEBUG_SHOW', False):
                    _image_ui = ImageUtils.cv2_to_QImage(draw_image.copy(), -1, -1)
                    if isinstance(_image_ui, Qt.QImage) and not _image_ui.isNull():
                        AppSlot.CameraUiSignal.emit(f'cell{CaseID}', _image_ui)
                AppTimeLoop.processGlobalEvents(1000)

            pass
        except Exception as e:
            AppUtils.print_Exception(e)

        return AnalysisIntegrationImages


    def SendCellToHeadEnd(self, CaseID: int, drawImage: np.ndarray):
        try:
            # self.webSocket.AppendItem.emit(Response.VideoStream(drawImage.copy()))
            self.webSocket.AppendItem.emit(Response.PreviewImage(drawImage.copy()))
            self.webSocket.AppendItem.emit(Response.SrcImageList(buffer=[drawImage.copy()]))
            if HeadEndShowMode.get('DEBUG_SHOW', False):
                _image_ui = ImageUtils.cv2_to_QImage(drawImage.copy(), -1, -1)
                if isinstance(_image_ui, Qt.QImage) and not _image_ui.isNull():
                    AppSlot.CameraUiSignal.emit(f'cell{CaseID}', _image_ui)
            AppTimeLoop.processGlobalEvents(1000)
        except Exception as e:
            AppUtils.print_Exception(e)


    @staticmethod
    def SaveCellModel(model: SlideModelInterface, CaseID: int, image: np.ndarray, isSaveYaml: bool = True):
        try:
            model.FocusingSavePath = ProcessCellFocusingPool.getCellSavePath(CaseID, model)
            case_model: SlideCaseModel = SlideCaseModel.copyInstance(model)
            LoggerModel: SlideLoggerModel = SlideLoggerModel.copyInstance(model)
            case_model.ID = None
            case_model.Level = ScanStatusLevel.HigKaryotypePicture_Status
            case_model.Index = CaseID
            case_model.FocusingSavePath = model.FocusingSavePath if model.has_FocusingSavePath else ''
            case_model.setImageSource(None)
            SlideCaseModel.append_all([case_model])
            LoggerModel.ID = None
            LoggerModel.Index = CaseID
            LoggerModel.Case_ID = case_model.ID
            LoggerModel.CaseModel = case_model
            SlideLoggerModel.append_all([LoggerModel])
            save_path, fmt = AppDBUtils.save_filename(case_model)
            if isinstance(save_path, str) and len(save_path) > 0:
                ImageSaveProcess(save_path, image.copy())
            if isSaveYaml:
                info_path, _ = AppDBUtils.info_filename(case_model)
                if isinstance(info_path, str) and len(info_path) > 0:
                    TextSaveProcess(info_path, case_model.to_YAML())
            isWrong = RECODE_SUCCEED
        except Exception as e:
            AppUtils.print_Exception(e)
            isWrong = RECODE_FAILURE
        model.setImageSource(image.copy())
        return isWrong

        pass

    """获取定焦图像保存路径"""
    @staticmethod
    def getCellSavePath(CaseID: int, model: SlideModelInterface) -> str:
        SpecimenPath: str
        try:
            if not model.has_SpecimenNumber:
                SpecimenPath: str = f'{model.CodeString}/'
            else:
                SpecimenPath: str = f'{model.SpecimenNumber}/slide{model.SlideNumber}/100X/'
            savePath: str = f'{AppConfig.PathConfig.absoluteFocusing_SavePath(SpecimenPath)}/cell{CaseID}/'
            filename: str = f'{savePath}/{model.index}_{model.ImageScore}.png'
        except Exception as e:
            AppUtils.print_Exception(e)
            filename = None
        return filename




    def initPools(self):
        self.initOnlyDrawPool       ()
        self.initWebSocketPool      ()

    def delePools(self):
        self.OnlyDrawPool       = None
        self.WebSocketPool      = None


    @property
    def isAvailable(self) -> bool:
        return self.isRunning() and self.hasWebSocketPool

    @property
    def hasOnlyDrawPool    (self) -> bool:
        return hasattr(self, 'OnlyDrawPool'   ) and isinstance(self.OnlyDrawPool   , DataOnlyDrawPool   )

    @property
    def hasWebSocketPool   (self) -> bool:
        return hasattr(self, 'WebSocketPool'  ) and isinstance(self.WebSocketPool  , DataWebSocketPool  )


    @property
    def onlyDraw     (self) -> DataOnlyDrawPool     :
        return None if not self.hasOnlyDrawPool    else self.OnlyDrawPool

    @property
    def webSocket    (self) -> DataWebSocketPool    :
        return None if not self.hasWebSocketPool   else self.WebSocketPool


    def initOnlyDrawPool    (self):
        if not self.hasOnlyDrawPool:
            self.OnlyDrawPool = DataOnlyDrawPool   .GetInstance()

    def initWebSocketPool   (self):
        if not self.hasWebSocketPool:
            self.WebSocketPool = DataWebSocketPool  .GetInstance()
