#!D:/IDE/anaconda3/envs/Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
@FileName：CameraAreaOperation.py
@Description：
@Author：XSH
@Time：2025/12/18 14:33
@Department：研发部
@Copyright：©2025 乐辰生物
"""
from abc                        import abstractmethod                       #
from PyQt5                      import Qt                                   #
from AppInterfaces.UiInterface  import UiInterface                          #
from AppInterfaces.globalSlot   import globalSlot, AppSlot                  #
from AppInterfaces.AppTimeLoop  import AppTimeLoop                          #
from AppCore.Contexts           import *                                    #
from AppCore.DBModels           import *                                    #
from AppCore.Levels             import *                                    #
from AppUtils.utils             import *                                    #
from AppSettings.SystemSetting  import SystemConfig, SystemSetting          #
class CameraAreaOperation(Qt.QWidget, UiInterface):
    AxisMoveSignal: Qt.pyqtSignal = Qt.pyqtSignal(object, object)
    MicroscopeMoveSignal: Qt.pyqtSignal = Qt.pyqtSignal(object)
    MicroscopeChangeSignal: Qt.pyqtSignal = Qt.pyqtSignal(object)
    IOLocker        : Qt.QReadWriteLock = Qt.QReadWriteLock()               #
    CameraUiSignal  : Qt.pyqtSignal     = Qt.pyqtSignal(object, object)     #
    Image           : Qt.QImage                                             #
    Icons           : Qt.QImage                                             #
    IsCrosshair     : bool                                                  #
    LinePoints      : list
    LastPoint       : Qt.QPoint
    MovePoint       : Qt.QPoint
    Offset_X        :  int
    Offset_Y        :  int
    Offset_Z        :  int
    def __init__(self, parent: Qt.QWidget = None):
        super(CameraAreaOperation, self).__init__(parent=parent)
        self.Initialization('CameraAreaOperation', self, parent)
        # self.initWidgetStyle()
        self.SlotCameraUiSignal(None, None)

    # def initWidgetStyle(self):
    #     from AppUtils.UiUtils import UiUtils
    #     self.setStyleSheet(UiUtils.getTransparentStyle())
    def initCameraUiSignal(self):
        TYPE: Qt.Qt.ConnectionType = Qt.Qt.ConnectionType(Qt.Qt.AutoConnection | Qt.Qt.UniqueConnection)
        try:
            AppSlot.CameraUiSignal.connect(slot=self.slot_CameraUiSignal, type=TYPE)

        except Exception as e:
            AppUtils.print_Exception(e)

    def deleCameraUiSignal(self):

        try:
            index: int = AppSlot.metaObject().indexOfMethod('CameraUiSignal')
            if index > -1:
                AppSlot.CameraUiSignal.disconnect(self.slot_CameraUiSignal)
        except Exception as e:
            AppUtils.print_Exception(e)

    def initValue(self):
        super(CameraAreaOperation, self).initValue()
        self.initImage()
        self.initIcons()
        self.IsCrosshair = False


    def initProperty(self):
        super(CameraAreaOperation, self).initProperty()
        from AppSettings.SystemSetting import SystemConfig
        self.IsCrosshair = SystemConfig.isDebugMode
        self.setFixedSize(640, 640)


    def initConnect(self):
        super(CameraAreaOperation, self).initConnect()
        TYPE: Qt.Qt.ConnectionType = Qt.Qt.ConnectionType(Qt.Qt.AutoConnection | Qt.Qt.UniqueConnection)
        AppSlot.ClearImageListSignal.connect(slot=self.SlotClearImageListSignal, type=TYPE)
        try:
            self.CameraUiSignal.connect(slot=self.SlotCameraUiSignal, type=TYPE)
        except Exception as e:
            AppUtils.print_Exception(e)

    def deleConnect(self):
        super(CameraAreaOperation, self).deleConnect()
        try:
            self.CameraUiSignal.disconnect(self.SlotCameraUiSignal)
        except Exception as e:
            AppUtils.print_Exception(e)

    def slot_CameraUiSignal(self, info: object, image: Qt.QImage):
        Locker: Qt.QWriteLocker = Qt.QWriteLocker(self.IOLocker)
        if isinstance(info, Qt.QImage):
            self.Image = Qt.QImage(info)
        elif isinstance(image, Qt.QImage):
            self.Image = Qt.QImage(image)
        else:
            self.Image = None
        self.repaint()

    def SlotGlobalCameraUiSignal(self, info: object, image: object):
        img: Qt.QImage = None
        if isinstance(info, np.ndarray):
            img = ImageUtils.cv2_to_QImage(info)
        elif isinstance(info, Qt.QImage):
            img = info
        elif isinstance(image, np.ndarray):
            img = ImageUtils.cv2_to_QImage(image)
        elif isinstance(image, Qt.QImage):
            img = image
        self.SlotCameraUiSignal(img, None)

    def SlotCameraUiSignal(self, info: object, image: Qt.QImage):
        # Locker: Qt.QWriteLocker = Qt.QWriteLocker(self.IOLocker)
        if isinstance(info, Qt.QImage):
            self.Image = Qt.QImage(info)
        elif isinstance(image, Qt.QImage):
            self.Image = Qt.QImage(image)
        else:
            self.Image = None
        self.repaint()

    def SlotClearImageListSignal(self, info = None, name = None):
        self.Image = None
        self.repaint()

    def setCrosshair(self, enable: (bool, int)):
        Locker: Qt.QWriteLocker = Qt.QWriteLocker(self.IOLocker)
        self.IsCrosshair = True if isinstance(enable, (bool, int)) and enable else False

    @property
    def isCrosshair(self) -> bool:
        Locker: Qt.QReadLocker = Qt.QReadLocker(self.IOLocker)
        if not self.hasIsCrosshair:
            self.IsCrosshair = False
        return self.IsCrosshair

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

    def drawImage(self) -> Qt.QPixmap:
        isDraw: bool = False
        if self.hasImage:
            # 将图片缩放到适合窗口大小
            scaled_image = Qt.QImage(self.Image)
            isDraw = True
        elif self.hasIcons:
            scaled_image = Qt.QImage(self.Icons)
        else:
            self.initIcons()
            scaled_image = Qt.QImage(self.Icons)
        src_size: Qt.QSize = self.size()
        scaled_image = scaled_image.scaled(src_size, Qt.Qt.IgnoreAspectRatio, Qt.Qt.SmoothTransformation)
        pixmap: Qt.QPixmap = Qt.QPixmap.fromImage(scaled_image)
        painter: Qt.QPainter = Qt.QPainter(pixmap)
        if self.IsCrosshair and isDraw:
            painter.setPen(Qt.QPen(Qt.Qt.red, 2))              # 设置画笔颜色为红色，宽度为2
            painter.drawLine(0                  , 0                 , 0                 , src_size.height() )
            painter.drawLine(0                  , 0                 , src_size.width()  , 0                 )
            painter.drawLine(0                  , src_size.height() , src_size.width()  , src_size.height() )
            painter.drawLine(src_size.width()   , 0                 , src_size.width()  , src_size.height() )
            # 绘制垂直线
            painter.drawLine(src_size.width() / 2, 0, src_size.width() / 2, src_size.height())
            # 绘制水平线
            painter.drawLine(0, src_size.height() / 2, src_size.width(), src_size.height() / 2)

        return pixmap


    def paintEvent(self, ev: Qt.QPaintEvent) -> None:
        painter = Qt.QPainter(self)
        painter.setRenderHint(Qt.QPainter.Antialiasing)

        pixmap: Qt.QPixmap = self.drawImage()
        # 计算居中位置
        # 绘制图片
        painter.drawPixmap(0, 0, pixmap)
        if self.hasLastPoint and self.hasMovePoint:
            painter.setPen(Qt.QPen(Qt.Qt.red, 2))
            painter.drawLine(self.LastPoint, self.MovePoint)
        return super(CameraAreaOperation, self).paintEvent(ev)


    def initImage(self):
        if not self.hasImage:
            Image = Qt.QImage(f"{Qt.QFileInfo(sys.argv[0]).absolutePath()}/Resource/Image/karyotype3.png")
            self.Image = Qt.QImage.scaled(Image, 2048, 2048, Qt.Qt.IgnoreAspectRatio, Qt.Qt.SmoothTransformation)


    def initIcons(self):
        if not self.hasIcons:
            Icons = Qt.QImage(f"{Qt.QFileInfo(sys.argv[0]).absolutePath()}/Resource/Image/karyotype3.png")
            self.Icons =  Qt.QImage.scaled(Icons, 2048, 2048, Qt.Qt.IgnoreAspectRatio, Qt.Qt.SmoothTransformation)

    def mousePressEvent(self, ev: Qt.QMouseEvent) -> None:
        self.Offset_Z = None
        self.MicroscopeMoveSignal.emit(self.Offset_Z)
        if ev.button() == Qt.Qt.LeftButton or ev.button() == Qt.Qt.RightButton:
            self.LastPoint = ev.pos()
            self.IsPress = True
            ev.accept()
            AppTimeLoop.processGlobalEvents(100)
            self.repaint()
        else:

            return super(CameraAreaOperation, self).mousePressEvent(ev)

    def mouseReleaseEvent(self, ev: Qt.QMouseEvent) -> None:
        self.Offset_Z = None
        self.MicroscopeMoveSignal.emit(self.Offset_Z)
        if ev.button() == Qt.Qt.LeftButton or ev.button() == Qt.Qt.RightButton:
            self.IsPress    = False
            self.LastPoint = None
            self.MovePoint = None
            self.Offset_X = None
            self.Offset_Y = None
            self.AxisMoveSignal.emit(self.Offset_X, self.Offset_Y)
            ev.accept()
            AppTimeLoop.processGlobalEvents(100)
            self.repaint()
        return super(CameraAreaOperation, self).mouseReleaseEvent(ev)

    def mouseDoubleClickEvent(self, ev: Qt.QMouseEvent) -> None:
        self.Offset_X = None
        self.Offset_Y = None
        self.AxisMoveSignal.emit(self.Offset_Y, self.Offset_Y)
        self.Offset_Z = None
        self.MicroscopeMoveSignal.emit(self.Offset_Z)
        super(CameraAreaOperation, self).mouseDoubleClickEvent(ev)

    def mouseMoveEvent(self, ev: Qt.QMouseEvent) -> None:
        if self.IsPress:
            self.MovePoint = Qt.QPoint(ev.pos())
            self.Offset_X: int = ev.x() - self.LastPoint.x()
            self.Offset_Y: int = ev.y() - self.LastPoint.y()
            self.AxisMoveSignal.emit(self.Offset_X, self.Offset_Y)
            ev.accept()
            AppTimeLoop.processGlobalEvents(100)
            self.repaint()
        else:
            return super(CameraAreaOperation, self).mouseMoveEvent(ev)

    def wheelEvent(self, ev: Qt.QWheelEvent) -> None:
        value: int = ev.angleDelta().y()
        if self.hasOffset_Z:
            if value > 0 and self.offset_z > 0:
                return super(CameraAreaOperation, self).wheelEvent(ev)
            elif value < 0 and self.offset_z < 0:
                return super(CameraAreaOperation, self).wheelEvent(ev)
            elif value == 0 and self.offset_z == 0:
                return super(CameraAreaOperation, self).wheelEvent(ev)
            self.Offset_Z = self.offset_z + ev.angleDelta().y()
        else:
            self.Offset_Z = self.offset_z + ev.angleDelta().y()
            self.MicroscopeChangeSignal.emit(self.offset_z)
            AppTimeLoop.processGlobalEvents(100)
        return super(CameraAreaOperation, self).wheelEvent(ev)


    @property
    def hasImage(self) -> bool:
        return hasattr(self, 'Image') and isinstance(self.Image, Qt.QImage)


    @property
    def hasIcons(self) -> bool:
        return hasattr(self, 'Icons') and isinstance(self.Icons, Qt.QImage)

    @property
    def move_point(self) -> Qt.QPoint:
        return Qt.QPoint(0, 0) if not self.hasMovePoint else self.MovePoint


    @property
    def hasLastPoint(self) -> bool:
        return hasattr(self, 'LastPoint') and isinstance(self.LastPoint, (Qt.QPoint, Qt.QPointF))

    @property
    def last_point(self) -> Qt.QPoint:
        return Qt.QPoint(0, 0) if not self.hasLastPoint else self.LastPoint

    @property
    def hasMovePoint(self) -> bool:
        return hasattr(self, 'MovePoint') and isinstance(self.MovePoint, (Qt.QPoint, Qt.QPointF))

    @property
    def hasOffset_X(self) -> bool:
        return self.has_field('Offset_X', (int, float))

    @property
    def hasOffset_Y(self) -> bool:
        return self.has_field('Offset_Y', (int, float))

    @property
    def hasOffset_Z(self) -> bool:
        return self.has_field('Offset_Z', (int, float))


    @property
    def offset_z(self) ->  int:
        return 0 if not self.hasOffset_Z else self.Offset_Z

    @property
    def offset_x(self) -> int:
        return 0 if not self.hasOffset_X else self.Offset_X

    @property
    def offset_y(self) -> int:
        return 0 if not self.hasOffset_Y else self.Offset_Y


