import os
import linuxcnc
from enum import Enum

from qtpy import uic
from qtpy.QtCore import Qt
from qtpy.QtWidgets import QWidget, QPushButton

from qtpyvcp.actions import machine, machine_actions
from qtpyvcp.plugins import getPlugin
from qtpyvcp.utilities import logger
from widgets.conversational.float_line_edit import FloatLineEdit

LOG = logger.getLogger(__name__)

STATUS = getPlugin('status')
TOOL_TABLE = getPlugin('tooltable')

INI_FILE = linuxcnc.ini(os.getenv('INI_FILE_NAME'))
CMD = linuxcnc.command()

class MoveMode(Enum):
    ABS = 1
    WCS = 2
    REL = 3

class UserTab(QWidget):
    def __init__(self, parent=None):
        super(UserTab, self).__init__(parent)
        ui_file = os.path.splitext(os.path.basename(__file__))[0] + ".ui"
        uic.loadUi(os.path.join(os.path.dirname(__file__), ui_file), self)

        STATUS.on.notify(self._update_controls)
        STATUS.all_axes_homed.notify(self._update_controls)

        STATUS.g5x_index.notify(self.update_wcs_label)
        self.update_wcs_label()
        
        self.edits: list[FloatLineEdit] = self.findChildren(FloatLineEdit)

        for fle in self.edits:
            fle.setEnabled(False)
            fle.editingFinished.connect(self.format_float)

        self.buttons: list[QPushButton] = self.findChildren(QPushButton)

        for btn in self.buttons:
            btn.setEnabled(False)
            btn.clicked.connect(self.move_axis)


    def format_float(self):
        if not isinstance(self.sender(), FloatLineEdit):
            return
        
        w: FloatLineEdit = self.sender()
        if w is None:
            LOG.debug(f"fn _format_float, sender None")
            return
        LOG.debug(f"fn: _format_float, sender name: {w.objectName()}")

        value = w.value()
        fmt = w.format_string
        val_fmt = fmt.format(value)
        w.setText(val_fmt)



    def update_wcs_label(self):
        idx = STATUS.g5x_index
        self.statuslabel_wcs.setText(f"WCS {idx}")
        # 'G54' if ch[0] == 1 else 'G55' if ch[0] == 2 else 'G56' if ch[0] == 3 else 'none'

    def move_relative(self):
        # machine_actions.jog.axis(axis='x', direction=1, distance=0.5)
        machine_actions.issue_mdi(f"G91 G0 X{self.fle_rel_x.value()}; G90")
        LOG.debug(f"fn: move_x. fle_wcs_x:{self.fle_rel_x.value()}")


    def move_axis(self):
        if not isinstance(self.sender(), QPushButton):
            return
        
        sender: QPushButton = self.sender()
        btn_name  = sender.objectName()
        LOG.debug(f"fn: move_axis. sender:{btn_name}")

        if "abs" in btn_name:
            dest_x = self.fle_abs_x.value()
            dest_y = self.fle_abs_y.value()
            dest_z = self.fle_abs_z.value()
            if "x" == btn_name[-1]:
                self.move_wcs(MoveMode.ABS, x=dest_x)
                return
            if "y" == btn_name[-1]:
                self.move_wcs(MoveMode.ABS, y=dest_y)
                return
            if "z" == btn_name[-1]:
                self.move_wcs(MoveMode.ABS, z=dest_z)
                return
            self.move_wcs(MoveMode.ABS, dest_x, dest_y, dest_z)
            LOG.debug(f"fn: move_wcs[ABS] x:{dest_x}, y:{dest_y}, z:{dest_z}")

        if "wcs" in btn_name:
            dest_x = self.fle_wcs_x.value()
            dest_y = self.fle_wcs_y.value()
            dest_z = self.fle_wcs_z.value()
            if "x" == btn_name[-1]:
                self.move_wcs(MoveMode.WCS, x=dest_x)
                return
            if "y" == btn_name[-1]:
                self.move_wcs(MoveMode.WCS, y=dest_y)
                return
            if "z" == btn_name[-1]:
                self.move_wcs(MoveMode.WCS, z=dest_z)
                return
            
            self.move_wcs(MoveMode.WCS, dest_x, dest_y, dest_z)
            LOG.debug(f"fn: move_wcs[WCS] x:{dest_x}, y:{dest_y}, z:{dest_z}")
        
        if "rel" in btn_name:
            dest_x = self.fle_rel_x.value()
            dest_y = self.fle_rel_y.value()
            dest_z = self.fle_rel_z.value()
            if "x" == btn_name[-1]:
                self.move_wcs(MoveMode.REL, x=dest_x)
                return
            if "y" == btn_name[-1]:
                self.move_wcs(MoveMode.REL, y=dest_y)
                return
            if "z" == btn_name[-1]:
                self.move_wcs(MoveMode.REL, z=dest_z)
                return
            
            self.move_wcs(MoveMode.REL, dest_x, dest_y, dest_z)
            LOG.debug(f"fn: move_wcs[REL] x:{dest_x}, y:{dest_y}, z:{dest_z}")


    
    def move_wcs(self, mode:MoveMode, x=None, y=None, z=None):
        match mode:
            case MoveMode.ABS: mdi_cmd = "G53 G0"
            case MoveMode.WCS: mdi_cmd = "G0"
            case MoveMode.REL: mdi_cmd = "G91 G0"

        if x is not None:
            mdi_cmd += f" X{x}"
        if y is not None:
            mdi_cmd += f" Y{y}"
        if z is not None:
            mdi_cmd += f" Z{z}"

        if mode == MoveMode.REL:
            mdi_cmd += " ;G90"
        
        LOG.debug(f"fn: move_wcs. MDI:{mdi_cmd}")
        machine_actions.issue_mdi(mdi_cmd)

    def _machine_ready(self) -> bool:
        LOG.debug(f"fn: machine_ready, on:{STATUS.on()}")
        LOG.debug(f"fn: machine_ready, all_axes_homed:{STATUS.all_axes_homed()}")
        return (
            STATUS.on()
            and STATUS.all_axes_homed()
        )

    def _update_controls(self, *args):
        ready = self._machine_ready()
        LOG.debug(f"Machine ready: {ready}")

        for btn in self.buttons:
            btn.setEnabled(ready)

        for fle in self.edits:
            fle.setEnabled(ready)

