#!D:/IDE/anaconda3/envs/Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
@FileName：ChamberScanningBusiness.py
@Description：
@Author：XSH
@Time：2025/11/15 13:03
@Department：研发部
@Copyright：©2025 乐辰生物
"""
import asyncio
import copy
from AppSettings.Settings import *
from PyQt5                                                      import Qt
from abc                                                        import abstractmethod, abstractclassmethod, abstractstaticmethod
from AppInterfaces.utils                                        import *
from AppUtils.utils                                             import *
from AppCore.Levels                                             import *
from AppCore.DBModels                                           import *
from AppInterfaces.Interfaces                                   import *
from AppCore.Requests                                           import *
from AppBackEnd.AppBusinessController                           import AppBusinessController, AppBusinessInterface
from AppBackEnd.BackEndEventBus.AppTaskController               import AppTaskController
class ChamberScanningBusiness(Qt.QObject, AppBusinessController):
    def __init__(self, parent: AppBusinessInterface = None):
        super(ChamberScanningBusiness, self).__init__(parent=parent if parent is not None else parent.m_Control)
        self.initialize()
        self.ScanLevel = ScanStatusLevel.Default_Status
        self.initModules(parent)

    def initScanLevel(self):
        self.ScanLevel = ScanStatusLevel.Default_Status

    def initModules(self, parent: AppBusinessInterface = None, **args):
        if isinstance(parent, AppBusinessInterface):
            self.Config                             = parent.config                       #
            self.SystemConfig                       = parent.system                       #
            self.HardWare                           = parent.devices                      #
            self.GlobalStatus                       = parent.status                       #
            self.Application                        = parent.application                  #
            self.Algorithm                          = parent.algorithm                    #
            self.EventBus                           = parent.eventBus                     #
            self.CheckBusiness                      = parent.CheckBusiness                #
            self.PickBusiness                       = parent.PickBusiness                 #
            self.DropBusiness                       = parent.DropBusiness                 #
            self.FocusingBusiness                   = parent.FocusingBusiness             #
            self.ScanningBusiness                   = parent.ScanningBusiness             #
            self.OilingBusiness                     = parent.OilingBusiness               #
            self.CellFocusingBusiness               = parent.CellFocusingBusiness         #

    def isValid(self) -> bool:
        return self.hasGlobalStatus and self.hasSystemConfig and self.hasConfig and self.hasDetector and self.hasMotion

    @property
    def isAvailable(self) -> bool:
        return self.isValid() and self.hasAxisX and self.hasAxisY and self.hasAxisZ and self.hasMicroscope and self.hasAxisH

    def Done(self, **kwargs):
        isWrong: int = RECODE_FAILURE
        self.status.setScanningStatus(self.ScanLevel)
        try:
            AutoScanMode          : bool  = AppConvert.ObjectConvert(kwargs.get('AutoScanMode'          , True), bool)
            keys: list[str] = list(kwargs.keys())
            _args: dict = {}
            for key in keys:
                if key == 'AutoScanMode':
                    pass
                else:
                    _args[key] = kwargs.get(key, None)
            isWrong = self.waitForChamberScanning(AutoScanMode=AutoScanMode, **_args)
        except Exception as e:
            AppUtils.print_Exception(e)
        if self.status.isExit:
            self.status.setScanningStatus(ScanStatusLevel.FinishScanning_Status)
        elif RECODE_SUCCEED == isWrong:
            self.status.setScanningStatus(self.ScanLevel)
        return

    def WaitDone(self, **kwargs) -> int:
        isWrong: int = RECODE_FAILURE
        self.status.setScanningStatus(self.ScanLevel)
        try:
            AutoScanMode: bool = AppConvert.ObjectConvert(kwargs.get('AutoScanMode', True), bool)
            keys: list[str] = list(kwargs.keys())
            _args: dict = {}
            for key in keys:
                if key == 'AutoScanMode':
                    pass
                else:
                    _args[key] = kwargs.get(key, None)
            isWrong = self.waitForChamberScanning(**_args)
        except Exception as e:
            AppUtils.print_Exception(e)
        if RECODE_SUCCEED == isWrong:
            self.status.setScanningStatus(self.ScanLevel)
        return isWrong

    def waitForChamberScanning(self, **args) -> int:
        MinRowNumber        : int
        MaxRowNumber        : int
        MaxChamberNumber    : int
        MinChamberNumber    : int
        chamber_number      : int
        row_number          : int
        tray_number         : int
        tray_index          : int
        default_objective   : int
        tray_length         : int
        is_tray_place       : bool
        front_limit_status  : bool
        tray_numbers        : list[int]
        tray_model          : SlideModelInterface
        MinChamberNumber    , MaxChamberNumber  = self.system.getChamberRange   ()
        isSafe: bool = AppConvert.ObjectConvert(args.get('isSafe', False), bool)
        isExit: bool = AppConvert.ObjectConvert(args.get('isExit', False), bool)
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_JUMPING:
            return RECODE_SUCCEED
        """处理扫描状态: 暂停 退出 跳过"""
        if SCANNING_STATUS == RECODE_CHANGED:
            return RECODE_SUCCEED
        """自动扫描 先检测片仓托盘"""
        if self.status.isAutoScanMode:
            isWrong = self.CheckChamberSlide(chamber_number=None, isSafe=isSafe)
            if RECODE_SUCCEED != isWrong or ScanStatusLevel.isCheckWarning(self.status.scanning_level):
                message_string: str = '检测片仓出错'
                if self.system.isEnglishMode:
                    message_string = 'Detect slide box errors'
                self.sendMessage(message_string)
                return isWrong

        self.eventBus.WebSocketPushScanningData()

        """判断载玻台是否有托盘"""
        self.waitForClearSlideTable()
        """处理扫描状态: 暂停 退出 跳过"""
        SCANNING_STATUS = self.process_scanning_status()
        if SCANNING_STATUS == RECODE_CHANGED:
            return RECODE_SUCCEED

        chamber_number      = MinChamberNumber      #
        tray_numbers        = TrayLevel.all()       #
        default_objective   = ObjectiveLevel.Objective1
        Objective           = ObjectiveModel.getConfig(default_objective)
        while chamber_number <= MaxChamberNumber:
            """判断挂钩是否在最后"""
            """判断载玻台是否有托盘"""
            """处理扫描状态: 暂停 退出 跳过"""
            SCANNING_STATUS = self.process_scanning_status()
            if SCANNING_STATUS == RECODE_CHANGED:
                self.waitForDropSlideTable(chamber_number)
                break
            is_tray_place = self.axis_h.get_tray_place_status()
            if is_tray_place:
                self.waitForClearSlideTable()
            """处理扫描状态: 暂停 退出 跳过"""
            SCANNING_STATUS = self.process_scanning_status()
            if SCANNING_STATUS == RECODE_CHANGED:
                self.waitForDropSlideTable(chamber_number)
                break
            """判断当前托盘是否可取"""
            isWarning, chamber_number = self.waitForSucceedPickAvailable(chamber_number=chamber_number)
            if RECODE_SUCCEED == isWarning and chamber_number <= MaxChamberNumber:
                """设置物镜为第一个位置 防止取放片过程中碰到物镜"""
                isWrong = self.microscope.set_objective(default_objective)
                if RECODE_SUCCEED != isWrong:
                    """处理取片错误"""
                    self.waitForClearSlideTable()
                    return isWrong
                """处理扫描状态: 暂停 退出 跳过"""
                SCANNING_STATUS = self.process_scanning_status()
                if SCANNING_STATUS == RECODE_CHANGED:
                    self.waitForDropSlideTable(chamber_number)
                    break
                """托盘取片 扫码"""
                isWrong = self.ChamberToSlideTable(chamber_number, isExit=False)
                if RECODE_SUCCEED != isWrong:
                    """处理取片错误"""
                    isWrong = self.waitForDropSlideTable(chamber_number)
                    if RECODE_SUCCEED != isWrong:
                        return isWrong
                    continue
                """扫描托盘载玻片"""
                for tray_number in tray_numbers:
                    SCANNING_STATUS = self.process_scanning_status()
                    if SCANNING_STATUS == RECODE_JUMPING:
                        self.status.setJumpScanning(False)
                    """处理扫描状态: 暂停 退出 跳过"""
                    if SCANNING_STATUS == RECODE_CHANGED:
                        break
                    isWrong = self.status.isPickAvailable(chamber_number=chamber_number, row_number=tray_number)
                    if RECODE_SUCCEED == isWrong:
                        self.ChangedScanningStatus(chamber_number, tray_number, ScanStatusLevel.Low_First_Focus_Status, ObjectiveLevel.Objective10)
                        self.waitForSlideScanning(chamber_number=chamber_number, row_number=tray_number, isSafe=isSafe)
                        scanning_status = ScanStatusLevel.ScanComplete_Status if RECODE_SUCCEED == isWrong and not ScanStatusLevel.isScanWarning(self.status.scanning_level) else self.status.scanning_level
                        self.ChangedScanningStatus(chamber_number, tray_number, scanning_status)
                        SCANNING_STATUS = self.process_scanning_status()
                        if SCANNING_STATUS == RECODE_JUMPING:
                            self.status.setJumpScanning(False)
                        """处理扫描状态: 暂停 退出 跳过"""
                        if SCANNING_STATUS == RECODE_CHANGED:
                            break
                """设置物镜为第一个位置 防止取放片过程中碰到物镜"""
                self.microscope.waitmove_z(Objective.Safe_Limit)
                self.microscope.set_objective(default_objective)
                self.manipulator.waithome_xy()
                """托盘放片"""
                isWrong = self.SlideTableToChamber(chamber_number, isExit=isExit)
                if RECODE_SUCCEED != isWrong:
                    """处理放片错误"""
                    self.waitForDropSlideTable(chamber_number)
                    return isWrong
                """处理扫描状态: 暂停 退出 跳过"""
                SCANNING_STATUS = self.process_scanning_status()
                if SCANNING_STATUS == RECODE_CHANGED:
                    self.waitForDropSlideTable(chamber_number)
                    break
            """处理扫描状态: 暂停 退出 跳过"""
            SCANNING_STATUS = self.process_scanning_status()
            if SCANNING_STATUS == RECODE_CHANGED:
                self.waitForDropSlideTable(chamber_number)
                break
            chamber_number += 1

        isWrong = self.finish_scanning()



        return isWrong



    def finish_scanning(self) -> int:
        isWrong: int = RECODE_SUCCEED
        isWrong = self.waitForDropSlideTable(self.status.ChamberGroupNumber)

        try:
            status: bool = self.axis_h.get_hook_back_limit_status()
            if not status:
                isWrong = self.axis_h.wait_empty_hook_return()
        except Exception as e:
            AppUtils.print_Exception(e)

        self.devices.waitmoveForSafe()
        return isWrong

    def waitForDropSlideTable(self, chamber_number: int = None, isSafe: bool = False, isExit: bool = False) -> int:
        """等待载玻台为空"""
        isWrong: int = RECODE_SUCCEED
        status: bool = self.axis_h.get_hook_back_limit_status()
        MinChamberNumber: int
        MaxChamberNumber: int
        ChamberNumber   : int
        MinChamberNumber, MaxChamberNumber = self.system.getChamberRange()
        if status:
            isDrop: bool = False
            if isinstance(chamber_number, int) and MinChamberNumber <= chamber_number <= MaxChamberNumber:
                ChamberNumber = chamber_number
            else:
                ChamberNumber = self.status.ChamberGroupNumber
            for tray_number in TrayLevel.all():
                isWrong = self.status.isPickAvailable(chamber_number=ChamberNumber, row_number=tray_number)
                if RECODE_SUCCEED == isWrong:
                    isDrop = True
                    break
            if isDrop:
                while True:
                    isWrong = self.DropChamberSlide(ChamberNumber, isSafe=isSafe, isExit=isExit)
                    if RECODE_SUCCEED == isWrong:
                        break
                    self.process_scanning_warning(f'放{ChamberNumber}号托盘错误', True)
                    self.clearWarning()

        return isWrong


