#!D:/IDE/anaconda3/envs python
# -*- coding: UTF-8 -*-
"""
 @Author: Administrator
 @FileName：HitBotModelView.py\n
 @DateTime: 2025/7/25 17:02\n
 @Author  ：xsh
"""
from abc import abstractmethod
from PyQt5 import Qt
from AppInterfaces.UiInterface import UiInterface, AppConvert, AppUtils
from AppCore.Contexts import *
from AppCore.DBModels import *
from AppCore.Levels import *
from AppUtils.UiUtils import UiUtils
from AppHeadEnd.Commons.ActionMenuBar   import ActionMenuBar

class HitBotModelView(Qt.QTableWidget, UiInterface):
    ActionMovesSignal   : Qt.pyqtSignal = Qt.pyqtSignal(object)
    ActionFlushSignal   : Qt.pyqtSignal = Qt.pyqtSignal(object, object, object)
    ActionChanged       : Qt.pyqtSignal = Qt.pyqtSignal(object, object, object)
    Model               : HitBotModel   #
    MenuBar             : ActionMenuBar #

    def __init__(self, data_model: HitBotModelInterface = None, parent: Qt.QWidget = None):
        super(HitBotModelView, self).__init__(parent=parent)
        self.Model = data_model if isinstance(data_model, HitBotModelInterface) else None
        self.Initialization('HitBotModelView', self, parent)
        self.initWidgetStyle()
        # self.flushFrame()

    def initWidgetStyle(self):
        self.setStyleSheet(UiUtils.getTableStyle())

    def initConnect(self):
        super(HitBotModelView, self).initConnect()
        TYPE: Qt.Qt.ConnectionType = Qt.Qt.ConnectionType(Qt.Qt.AutoConnection | Qt.Qt.UniqueConnection)
        self.MenuBar       .ActionSignal.connect(slot=self.ActionSignalSlot             , type=TYPE)
        self.cellChanged                .connect(slot=self.cellChangedSlot              , type=TYPE)
        self.ActionChanged              .connect(slot=self.ActionChangedSlot            , type=TYPE)

    def ActionSignalSlot (self, signal: str):
        if not isinstance(signal, str):
            return
        self.initModel()
        # '刷新', '移动', '添加', '保存', '删除', '清空'
        if '刷新' == signal:
            self.flushFrame()
            return
        if '添加' == signal:
            model = self.Model.getMaxPrimaryItem()
            if not model:
                return
            self.append_new_action(model)
            return
        if '清空' == signal:
            self.clearTable()
            return

        item: Qt.QTableWidgetItem = self.currentItem()
        if not item:
            return
        row = self.row(item)
        if '保存' == signal:
            self.update_row_action(row)
            return
        if '删除' == signal:
            self.remove_row_action(row)
            return
        request: HitBotModelInterface = self.get_row_action(row)
        if not isinstance(request, HitBotModelInterface):
            return
        if '移动' == signal:
            self.ActionMovesSignal.emit(request)
            return

    def cellChangedSlot  (self, row: int, column: int):
        self.initModel()
        self.update_row_action(row)

    def ActionChangedSlot(self, widget: Qt.QWidget, row_number: int, hitbot: HitBotModelInterface):
        if id(self) != id(widget):
            return
        if not isinstance(hitbot, HitBotModelInterface):
            return
        model: HitBotModelInterface = self.get_row_action(row_number)
        if not model:
            return
        model.as_field(hitbot.to_field(False))
        if not model or not model.has_ID:
            return
        model.model_update(model.to_field(False), self.Model.__class__.ID == model.ID)
        self.updateTableData()
        pass

    def mousePressEvent(self, e: Qt.QMouseEvent) -> None:
        if e.button() == Qt.Qt.RightButton:
            self.IsPress = True
        super(HitBotModelView, self).mousePressEvent(e)

    def mouseReleaseEvent(self, e: Qt.QMouseEvent) -> None:
        if e.button() == Qt.Qt.RightButton:
            if self.IsPress:
                self.MenuBar.draw(e.globalPos())
                self.IsPress = False
        super(HitBotModelView, self).mouseReleaseEvent(e)

    """刷新"""
    def flushFrame(self):
        self.updateTableData()

    """删除"""
    def remove_row_action(self, row: int):
        model = self.get_row_action(row)
        if not model or not model.has_ID:
            return
        model.remove(self.Model.__class__.ID ==model.ID)
        self.updateTableData()
    """清空"""
    def clearTable(self):
        self.initModel()
        self.Model.clear()
        self.updateTableData()
    """添加"""
    def append_new_action(self, hitbot: HitBotModelInterface):
        if isinstance(hitbot, HitBotModelInterface):
            model = self.Model.copy()
            model.as_field(hitbot.to_field(False))
            self.Model.append_all([model])
            self.updateTableData()

    """保存"""
    def update_row_action(self, row: int):
        model = self.get_row_action(row)
        if not model or not model.has_ID:
            return
        model.model_update(model.to_field(False), self.Model.__class__.ID == model.ID)
        # self.updateTableData()

    def updateTableData(self):
        self.initModel()
        model_type = self.Model.__class__
        models: list[model_type] = self.Model.all()
        if models is None:
            return
        self.blockSignals(True)
        self.setRowCount(len(models))
        for row, action in enumerate(models):
            self.append_row_action(row, action)
            Qt.QCoreApplication.processEvents(Qt.QEventLoop.AllEvents, 50)
        self.blockSignals(False)

    def append_row_action(self, row: int, hitbot: HitBotModelInterface):
        buffer: object
        item: Qt.QTableWidgetItem
        box: Qt.QComboBox
        dct_move_types: dict[str, object] = HitBotMoveType.toItem()
        AxisLevel_items: dict[str, object] = AxisLevel.toHitBotItem()
        for col, _property in enumerate(self.Model.__field__):
            buffer = getattr(hitbot, _property, None)
            if 'efg_distance' == _property:
                box = Qt.QComboBox(self)
                box.addItems(['打开', '关闭', 'None'])
                box.setProperty('hitbot_field', _property)
                box.setProperty('row_number', row)
                index = 2
                if hitbot.isGripperON():
                    index = 0
                elif hitbot.isGripperOFF():
                    index = 1
                box.setCurrentIndex(index)
                self.setTableWidgetComboBox(row, col, self, box)
            elif 'isScanning' == _property:
                box = Qt.QComboBox(self)
                box.addItems(['不扫码', '扫码'])
                box.setProperty('hitbot_field', _property)
                box.setProperty('row_number', row)
                index = 0
                if hitbot.has_isScanning:
                    index = 1 if hitbot.IsScanning() else 0
                box.setCurrentIndex(index)
                self.setTableWidgetComboBox(row, col, self, box)

            elif 'movetype' == _property:
                box = Qt.QComboBox(self)
                box.addItems([f'{key}' for key, value in dct_move_types.items()])
                box.setProperty('hitbot_field', _property)
                box.setProperty('row_number', row)
                box.setCurrentText(HitBotMoveType.toString(buffer))
                self.setTableWidgetComboBox(row, col, self, box)
            elif 'axistype' == _property:
                box = Qt.QComboBox(self)

                box.addItems([f'{key}' for key, value in AxisLevel_items.items()])
                box.setProperty('hitbot_field', _property)
                box.setProperty('row_number', row)
                box.setCurrentText(AxisLevel.toHitBotString(buffer))
                self.setTableWidgetComboBox(row, col, self, box)
            else:
                item = Qt.QTableWidgetItem()
                item.setData(Qt.Qt.UserRole, buffer)
                if isinstance(buffer, float):
                    item.setData(Qt.Qt.DisplayRole, buffer)
                else:
                    item.setData(Qt.Qt.DisplayRole, buffer)
                if buffer is not None:
                    item.setFlags(item.flags() | Qt.Qt.ItemIsEditable)
                else:
                    item.setFlags(item.flags() & (~Qt.Qt.ItemIsEditable))
                self.setTableWidgetItem(row, col, self, item)

    def get_row_action(self, row: int) -> HitBotModelInterface:
        self.initModel()
        model_type = self.Model.__class__
        model: model_type = self.Model.copy()

        item: Qt.QTableWidgetItem
        box: Qt.QComboBox
        for col, _property in enumerate(self.Model.__field__):
            if 'efg_distance' == _property:
                box = self.cellWidget(row, col)
                self.update_box(box, model)
            elif 'movetype' == _property:
                box = self.cellWidget(row, col)
                self.update_box(box, model)
            elif 'isScanning' == _property:
                box = self.cellWidget(row, col)
                self.update_box(box, model)
            elif 'axistype' == _property:
                box = self.cellWidget(row, col)
                self.update_box(box, model)
            else:
                item = self.item(row, col)
                self.update_item(row, col, item, model)

        return model
        pass

    def refresh_row_col_action(self, row: int, col: int, model: HitBotModelInterface):
        if not isinstance(model, HitBotModelInterface):
            return


        if 0 <= col < len(self.Model.__field__):
            item: Qt.QTableWidgetItem
            box: Qt.QComboBox
            _property: str = self.Model.__field__[col]
            if 'efg_distance' == _property:
                box = self.cellWidget(row, col)
                self.update_box(box)
            elif 'movetype' == _property:
                box = self.cellWidget(row, col)
                self.update_box(box)
            elif 'isScanning' == _property:
                box = self.cellWidget(row, col)
                self.update_box(box)
            elif 'axistype' == _property:
                box = self.cellWidget(row, col)
                self.update_box(box)
            else:
                item = self.item(row, col)
                self.update_item(row, col, item)

    def update_box(self, box: Qt.QComboBox, model: HitBotModelInterface):
        if not isinstance(box, Qt.QComboBox) or not isinstance(model, HitBotModelInterface):
            return
        _property: str = box.property('hitbot_field')
        row_number: int = box.property('row_number')
        grippers: list[str] = ['打开', '关闭', 'None']
        codes: list[str] = ['不扫码', '扫码']
        if not isinstance(_property, str) or not isinstance(row_number, int):
            return
        if _property in self.Model.__field__:
            if 'efg_distance' == _property:
                if box.currentText() == grippers[0]:
                    model.setGripperON()
                elif box.currentText() == grippers[1]:
                    model.setGripperOFF()
                else:
                    model.efg_distance = None
            elif 'isScanning' == _property:
                if box.currentText() == codes[1]:
                    model.isScanning = 1
                else:
                    model.isScanning = None
            elif 'movetype' == _property:
                model.movetype = HitBotMoveType.toValue(box.currentText())
            elif 'axistype' == _property:
                model.axistype = AxisLevel.toHitBotItem().get(box.currentText(), None)
                pass

    def update_item(self, row: int, col: int, item: Qt.QTableWidgetItem, model: HitBotModelInterface):
        if not isinstance(item, Qt.QTableWidgetItem) or not isinstance(model, HitBotModelInterface):
            return
        if not isinstance(row, int) or not isinstance(col, int):
            return
        if  0 <= col < len(self.Model.__field__):
            _property: str = self.Model.__field__[col]
            buffer = item.data(Qt.Qt.DisplayRole)
            setattr(model, _property, buffer)

    @staticmethod
    def setTableWidgetComboBox(row: int, column: int, table: Qt.QTableWidget, box: Qt.QComboBox):
        if not isinstance(row, int) or not isinstance(column, int):
            return
        if not isinstance(table, Qt.QTableWidget) or not isinstance(box, Qt.QComboBox):
            return
        table.setCellWidget(row, column, box)

    @staticmethod
    def setTableWidgetItem(row: int, column: int, table: Qt.QTableWidget, item: Qt.QTableWidgetItem):
        if not isinstance(row, int) or not isinstance(column, int):
            return
        if not isinstance(table, Qt.QTableWidget) or not isinstance(item, Qt.QTableWidgetItem):
            return
        table.setItem(row, column, item)

    def initValue(self):
        super(HitBotModelView, self).initValue()
        self.initMenuBar    ()

    def initProperty(self):
        super(HitBotModelView, self).initProperty()
        if not self.hasControl or not isinstance(self.m_Control, Qt.QTableWidget):
            return
        if not self.hasModel:
            return
        # 设置全部单元格可编辑
        max_length: int = len(self.Model.__field__)
        self.setColumnCount(max_length)
        self.setHorizontalHeaderLabels(self.Model.__field__)
        header = self.horizontalHeader()
        header.setSectionResizeMode(Qt.QHeaderView.Stretch)  # Make columns stretch to fill width
        header.setSectionResizeMode(0, Qt.QHeaderView.Interactive)
        header.setStretchLastSection(True)  # Stretch last column
        header.setSectionResizeMode(Qt.QHeaderView.Custom)
        # 设置表头字体大小
        headerFont = header.font()
        headerFont.setPixelSize(10)
        header.setFont(headerFont)

        self.setHorizontalHeader(header)
        for index, _property in enumerate(self.Model.__field__):
            self.setColumnWidth(index, 150)
        self.setMinimumWidth(800)
        self.setMinimumHeight(200)
        # Set fixed row height
        self.verticalHeader().setDefaultSectionSize(40)
        # Set table properties
        self.setSelectionBehavior(Qt.QTableWidget.SelectRows)  # Select entire rows
        self.setSelectionMode(Qt.QTableWidget.SingleSelection)  # Single row selection
        self.setEditTriggers(Qt.QTableWidget.CurrentChanged)  # Read-only
        self.setAlternatingRowColors(False)  # 禁用隔行变色
        self.setShowGrid(True)  # Show grid lines
        self.verticalHeader().setVisible(False)  # Hide row numbers
        header.setSectionResizeMode(Qt.QHeaderView.Interactive)


    def initModel   (self):
        if not self.hasModel  :
            self.Model   = HitBotModel()
    def initMenuBar (self):
        if not self.hasMenuBar:
            self.MenuBar = ActionMenuBar(signals=['刷新', '移动', '添加', '保存', '删除', '清空'])

    @property
    def hasModel   (self) -> bool:
        return hasattr(self, 'Model'   ) and isinstance(self.Model  , HitBotModelInterface  )

    @property
    def hasMenuBar (self) -> bool:
        return hasattr(self, 'MenuBar' ) and isinstance(self.MenuBar, ActionMenuBar)
