#!D:/IDE/anaconda3/envs/Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
@FileName：FocusingController.py
@Description：
@Author：XSH
@Time：2025/12/22 9:03
@Department：研发部
@Copyright：©2025 乐辰生物
"""
import sys
import os
from PyQt5                                                      import Qt                                               #
from AppSettings.Settings                                       import *                                                #
from AppInterfaces.utils                                        import *                                                #
from AppCore.Levels                                             import *                                                #
from AppCore.Contexts                                           import *                                                #
from AppCore.DBModels                                           import *                                                #
from AppUtils.utils                                             import *                                                #
from AppInterfaces.UiInterface                                  import UiInterface                                      #
from AppBackEnd.AppBusinessInterface                            import AppBusinessInterface                             #
from AppHeadEnd.Commons.OperationViews.FocusingOperation        import FocusingOperation                                #
from AppHeadEnd.Commons.OperationViews.FocusButtonOperation     import FocusButtonOperation                             #
from AppHeadEnd.ControllerFrames.ControlFrameInterface          import ControlFrameInterface                            #


class FocusingController(Qt.QWidget, ControlFrameInterface, SingletonInterface):
    Button      : FocusButtonOperation      #
    Tables      : FocusingOperation         #
    Locker      : Qt.QMutex = Qt.QMutex()   #
    Level       : int                       #
    Objective   : ObjectiveModel            #

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

    def __init__(self, parent: Qt.QWidget = None):
        super(FocusingController, self).__init__(parent=parent)
        self.Initialization('物镜校准界面', self, parent)


    def setBusiness(self, business: AppBusinessInterface):
        self.Business = business


    def initConnect(self):
        super(FocusingController, self).initConnect()
        TYPE: Qt.Qt.ConnectionType = Qt.Qt.ConnectionType(Qt.Qt.AutoConnection | Qt.Qt.UniqueConnection)
        self.Button.NextButton.clicked      .connect(self.SlotNextButtonClicked     , TYPE)
        self.Button.PrevButton.clicked      .connect(self.SlotPrevButtonClicked     , TYPE)
        self.Button.DoneButton.clicked      .connect(self.SlotDoneButtonClicked     , TYPE)
        self.Button.PositionButton.clicked  .connect(self.SlotPositionButtonClicked , TYPE)
        self.Tables.PositionChangedSignal   .connect(self.SlotPositionChanged       , TYPE)

    def SlotPositionButtonClicked(self):
        if not self.isAvailable():
            return
        isWrong, objective = self.microscope.get_objective()
        if RECODE_SUCCEED != isWrong or not isinstance(objective, int):
            return

        x: float
        y: float
        z: float
        self.Level = objective
        isWrong, z = self.microscope.get_position()
        if RECODE_SUCCEED != isWrong or not isinstance(z, (int, float)):
            return
        isWrong, x, y = self.manipulator.position_xy()
        if RECODE_SUCCEED != isWrong or not isinstance(x, (int, float)) or not isinstance(y, (int, float)):
            return
        data: FocusingContext = self.Tables.getCalibrateData(objective)
        if not isinstance(data, FocusingContext):
            return
        # 263步是1um 263158 是1mm 131579 0.5mm 2630是10um
        MIC_MAX_MOVE_VELOCITY: float = 263158
        MIC_MAX_MOVE_LENGTH: int = 263158
        MAX_MIC_MOVE_LENGTH: int = 6800000
        focusing_range: int = self.Button.focusing_range
        self.Tables.changedPosition(self.level, x, y, z)
        if objective <= ObjectiveLevel.Objective10:
            """如果物镜为10 则设置定焦参数"""
            Focusing_Lower  : float = z - focusing_range
            Focusing_Upper  : float = min(max(Focusing_Lower, z + focusing_range)              , MAX_MIC_MOVE_LENGTH)
            Upper_Limit     : float = min(max(Focusing_Upper, Focusing_Upper + focusing_range) , MAX_MIC_MOVE_LENGTH)
            ObjectiveModel.changed({ObjectiveModel.Focus_Lower_Limit: Focusing_Lower,
                                    ObjectiveModel.Focus_Upper_Limit: Focusing_Upper,
                                    ObjectiveModel.Upper_Limit      : Upper_Limit   ,
                                    ObjectiveModel.OilFocalDistance : 0             ,
                                    ObjectiveModel.FocalDistance    : 0             ,
                                    ObjectiveModel.FocusingOffset   : 0             ,
                                    }, ObjectiveModel.Level == ObjectiveLevel.Objective10)


        if objective > ObjectiveLevel.Objective10:
            """如果物镜为20 40 63 100 则计算物镜和10倍物镜之间的差距"""
            data_10x: FocusingContext = self.Tables.getCalibrateData(ObjectiveLevel.Objective10)
            if not isinstance(data_10x, FocusingContext):
                return
            offsetX: float = round(data.XPosition - data_10x.XPosition, 4)
            offsetY: float = round(data.YPosition - data_10x.YPosition, 4)
            offsetZ: float = round(data.ZPosition - data_10x.ZPosition, 4)
            self.Tables.changedOffset(self.level, offsetX, offsetY, offsetZ)
            Focusing_Lower  : float =  z - focusing_range
            Focusing_Upper  : float =  min(max(Focusing_Lower, z + focusing_range)              , MAX_MIC_MOVE_LENGTH)
            Upper_Limit     : float =  min(max(Focusing_Upper, Focusing_Upper + focusing_range) , MAX_MIC_MOVE_LENGTH)
            ObjectiveModel.changed({ObjectiveModel.Focus_Lower_Limit: Focusing_Lower,
                                    ObjectiveModel.Focus_Upper_Limit: Focusing_Upper,
                                    ObjectiveModel.Upper_Limit      : Upper_Limit   ,
                                    ObjectiveModel.OilFocalDistance : offsetZ       ,
                                    ObjectiveModel.FocalDistance    : offsetZ       ,
                                    ObjectiveModel.FocusingOffset   : offsetZ       ,
                                    }, ObjectiveModel.Level == ObjectiveLevel.Objective10)


    def SlotPositionChanged(self, data: FocusingContext):
        if not self.isAvailable():
            return
        if not isinstance(data, FocusingContext) or not data.hasLevel:
            return
        objective: int = data.Level

        Objective: ObjectiveModel = ObjectiveModel.getConfig(objective)
        if not isinstance(Objective, ObjectiveModel):
            return
        self.microscope.init_z_range()
        self.microscope.set_z_speed(Objective.Default_Speed)
        self.microscope.set_z_move_mode(1)
        self.microscope.waitmove(Objective.Safe_Limit)
        self.manipulator.waitmove_xy(data.XPosition, data.YPosition)
        if objective == ObjectiveLevel.Objective63 or objective == ObjectiveLevel.Objective100:
            Qt.QMessageBox.information(self, '提示', '清滴油')
        self.microscope.set_objective(objective)
        # if int(data.ZPosition) > Objective.Safe_Limit:
        #     self.microscope.waitmove(Objective.Safe_Limit)
        # else:
        self.microscope.waitmove(int(data.ZPosition))

    def SlotNextButtonClicked(self):
        self.Level = min(max(self.level + 1, ObjectiveLevel.Objective1), ObjectiveLevel.ObjectiveNone)
        self.Objective = ObjectiveModel.getConfig(self.level)
        self.Tables.setObjective(self.level)


    def SlotPrevButtonClicked(self):
        self.Level = min(max(self.level - 1, ObjectiveLevel.Objective1), ObjectiveLevel.ObjectiveNone)
        self.Objective = ObjectiveModel.getConfig(self.level)
        self.Tables.setObjective(self.level)

    def SlotDoneButtonClicked(self):
        pass

    def SlotStartButtonClicked(self):
        self.Level = ObjectiveLevel.Objective10
        self.Objective = ObjectiveModel.getConfig(self.level)
        self.Tables.setObjective(self.level)

    def initValue(self):
        super(FocusingController, self).initValue()
        self.initLevel      ()
        self.initObjective  ()
        self.initButton     ()
        self.initTables     ()

    def initProperty(self):
        super(FocusingController, self).initProperty()
        self.initWindowIcon()
        self.setWindowFlags(self.windowFlags() | Qt.Qt.WindowStaysOnTopHint)
        self.setFixedSize(1000, 350)
        self.Tables.flushItems()
        self.Tables.setObjective(self.level)


    def initLayouts(self):
        if self.hasWindowLayouts:
            return
        main_layout: Qt.QVBoxLayout = Qt.QVBoxLayout()
        main_layout.setSpacing(0)
        main_layout.setContentsMargins(0, 0, 0, 0)

        main_layout.addWidget(self.Tables)
        main_layout.addWidget(self.Button)

        self.setLayout(main_layout)

    def initButton(self):
        if not self.hasButton:
            self.Button = FocusButtonOperation(self)
    def initTables(self):
        if not self.hasTables:
            self.Tables = FocusingOperation(self)
    def initLevel(self):
        if not self.hasLevel:
            self.Level = ObjectiveLevel.Objective10

    def initObjective(self):
        if not self.hasObjective:
            self.Objective = ObjectiveModel.getConfig(self.level)

    @property
    def hasButton(self) -> bool:
        return self.has_field('Button', FocusButtonOperation)

    @property
    def hasTables(self) -> bool:
        return self.has_field('Tables', FocusingOperation   )

    @property
    def hasLevel       (self) -> bool:
        return self.has_field('Level'        , int)

    @property
    def hasObjective   (self) -> bool:
        return self.has_field('Objective'    , ObjectiveModel)


    @property
    def objective(self) -> ObjectiveModel:
        self.initObjective()
        return self.Objective


    @property
    def level(self) -> int:
        self.initLevel()
        return self.Level
