import os
import sys
import linuxcnc

from PySide6.QtCore import QTimer
from PySide6.QtWidgets import QWidget, QLabel

from qtpyvcp import hal
from qtpyvcp.widgets.button_widgets.action_button import ActionButton

# ASSUMPTION: this file lives at <config_root>/user_buttons/user_buttons/user_buttons.py,
# two levels below the config root, matching the same nesting pattern as user_tabs.
# Adjust the number of ".." if your actual folder depth differs.
_SHARED_WIDGETS_DIR = os.path.abspath(
    os.path.join(os.path.dirname(__file__), "..", "..", "shared_widgets")
)
if _SHARED_WIDGETS_DIR not in sys.path:
    sys.path.insert(0, _SHARED_WIDGETS_DIR)

from illuminated_label import IlluminatedLabelBinder

from qtpyvcp.plugins import getPlugin
from qtpyvcp.utilities import logger
from qtpyvcp.actions import bindWidget, InvalidAction
from qtpyvcp.utilities.runtime_ui_loader import load_ui as load_runtime_ui

LOG = logger.getLogger(__name__)

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

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


def _load_ui(ui_path, parent):
    return load_runtime_ui(ui_path, parent)


class UserButton(QWidget):

    # --- PAUSED blink rate -----------------------------------------------
    # Time between blink toggles, in milliseconds. Lower = faster blink.
    RUN_STATE_BLINK_INTERVAL_MS = 400
    # -----------------------------------------------------------------------

    RUN_STATE_STYLE_STOPPED = (
        "QLabel{"
        "color: white;"
        "background-color: rgb(75, 75, 75);"
        "border-style: solid;"
        "border-color: rgb(116, 116, 116);"
        "border-width: 1px;"
        "border-radius: 4px;"
        "padding-top: 4px;"
        "padding-bottom: 4px;"
        "padding-right: 1px;"
        "}"
    )
    RUN_STATE_STYLE_RUNNING = (
        "QLabel{"
        "color: black;"
        "background-color: rgb(80, 255, 80);"
        "border-style: solid;"
        "border-color: rgb(116, 116, 116);"
        "border-width: 1px;"
        "border-radius: 4px;"
        "padding-top: 4px;"
        "padding-bottom: 4px;"
        "padding-right: 1px;"
        "}"
    )
    RUN_STATE_STYLE_PAUSED_LIT = (
        "QLabel{"
        "color: black;"
        "background-color: rgb(255, 255, 100);"
        "border-style: solid;"
        "border-color: rgb(116, 116, 116);"
        "border-width: 1px;"
        "border-radius: 4px;"
        "padding-top: 4px;"
        "padding-bottom: 4px;"
        "padding-right: 1px;"
        "}"
    )
    # PAUSED's dark blink phase reuses the same look as STOPPED
    RUN_STATE_STYLE_PAUSED_DARK = RUN_STATE_STYLE_STOPPED

    def __init__(self, parent=None):
        super(UserButton, self).__init__(parent)
        # The .ui is named after this file, so a copied folder just works.
        ui_file = os.path.splitext(os.path.basename(__file__))[0] + ".ui"
        ui_path = os.path.join(os.path.dirname(__file__), ui_file)
        self.ui = _load_ui(ui_path, self)
        self._bind_action_buttons()
        self._bind_indicator_labels()
        self._bind_run_state_indicator()

    def _bind_action_buttons(self):
        # Explicitly bind dynamic buttons in case property-based binding was skipped.
        for button in self.findChildren(ActionButton):
            action_name = button.property("actionName")
            if not action_name:
                continue
            try:
                bindWidget(button, str(action_name))
            except InvalidAction:
                LOG.warning("Invalid action for user button %s: %s", button.objectName(), action_name)

    def _bind_indicator_labels(self):
        # Any QLabel with an 'indicatorPinName' dynamic property (set from
        # Qt Designer's Property Editor, no Python needed) becomes an
        # illuminated indicator. 'indicatorStyle' (on-color) defaults to
        # "green", 'indicatorFlashStyle' (flash-color) defaults to "red" --
        # both are independent and can be mixed freely.
        self._indicators = []
        for label in self.ui.findChildren(QLabel):
            pin_name = label.property("indicatorPinName")
            if not pin_name:
                continue
            style = label.property("indicatorStyle") or "green"
            flash_style = label.property("indicatorFlashStyle") or "red"
            font_size = label.property("indicatorFontSize") or 24
            self._indicators.append(
                IlluminatedLabelBinder(
                    label, str(pin_name), style=str(style),
                    flash_style=str(flash_style), font_size=int(font_size)
                )
            )

    def _bind_run_state_indicator(self):
        # STOPPED/RUNNING/PAUSED text+color, driven directly via
        # linuxcnc.stat() polling rather than Widget Rules -- this widget
        # needs its text to change (which our Rules attempts couldn't blink
        # reliably) and PAUSED needs to blink, which Widget Rules can't do
        # without a periodically-ticking channel we don't have confirmed.
        self._run_state_label = self.ui.findChild(QLabel, "hallabel_2")
        if self._run_state_label is None:
            LOG.warning("Could not find hallabel_2 for run-state indicator")
            return

        self._run_state_stat = linuxcnc.stat()
        self._run_state_blink_phase = False

        self._run_state_timer = QTimer()
        self._run_state_timer.timeout.connect(self._update_run_state)
        self._run_state_timer.start(self.RUN_STATE_BLINK_INTERVAL_MS)

        self._update_run_state()

    def _update_run_state(self):
        try:
            self._run_state_stat.poll()
        except linuxcnc.error:
            return

        state = self._run_state_stat.interp_state
        label = self._run_state_label

        if state == linuxcnc.INTERP_PAUSED:
            self._run_state_blink_phase = not self._run_state_blink_phase
            label.setText("PAUSED")
            label.setStyleSheet(
                self.RUN_STATE_STYLE_PAUSED_LIT
                if self._run_state_blink_phase
                else self.RUN_STATE_STYLE_PAUSED_DARK
            )
        elif state == linuxcnc.INTERP_IDLE:
            label.setText("STOPPED")
            label.setStyleSheet(self.RUN_STATE_STYLE_STOPPED)
        else:  # INTERP_READING or INTERP_WAITING
            label.setText("RUNNING")
            label.setStyleSheet(self.RUN_STATE_STYLE_RUNNING)
