from PyQt6.QtWidgets import (
    QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel,
    QFrame, QGridLayout, QSizePolicy, QLineEdit, QApplication,
)
from PyQt6.QtCore import Qt, QTimer, QPointF, QRectF, QEvent
from PyQt6.QtGui import QFont, QPainter, QColor, QBrush, QPen, QDoubleValidator
from utils.config_parse import ConfigParse
from utils.floating_keyboard import FloatingKeyboard

MOVE_STEP = 10  # 每次点击移动 mm (保留备用)

MOVE_DETECT_MS = 100


class JoystickWidget(QWidget):
    """圆形 XY 摇杆 — 拖动小圆控制方向，松开回中，越远越快"""

    def __init__(self, parent=None, max_speed=3000):
        super().__init__(parent)
        self.setFixedSize(320, 320)
        self.setMouseTracking(True)

        self._max_speed = max_speed  # 最大进给速度 mm/min
        self._radius_outer = 140      # 外圈半径
        self._radius_inner = 30       # 内圈小圆半径
        self._deadzone = 10           # 死区像素

        # 当前小圆偏移（相对中心，像素）
        self._dx = 0.0
        self._dy = 0.0
        self._pressed = False

        # 定时发送 GCode
        self._move_timer = QTimer(self)
        self._move_timer.setInterval(120)  # ~8次/秒
        self._move_timer.timeout.connect(self._emit_move)

        # 回调（上层设置）
        self.on_move = None  # callable(dx_norm, dy_norm, feedrate)

    def _emit_move(self):
        """定时器触发：计算速度方向并回调"""
        dist = (self._dx ** 2 + self._dy ** 2) ** 0.5
        if dist < self._deadzone:
            return
        ratio = min(dist / (self._radius_outer - self._radius_inner), 1.0)
        # 速度映射：30% ~ 100% * max_speed
        speed = int((0.3 + ratio * 0.7) * self._max_speed)
        if dist > 0:
            nx = self._dx / dist
            ny = self._dy / dist
            if self.on_move:
                self.on_move(nx, ny, speed)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)
        cx, cy = self.width() / 2, self.height() / 2

        # 外圈背景
        painter.setBrush(QBrush(QColor("#2a2a2a")))
        painter.setPen(QPen(QColor("#666666"), 3))
        painter.drawEllipse(QPointF(cx, cy), self._radius_outer, self._radius_outer)

        # 十字准线（浅）
        painter.setPen(QPen(QColor("#555555"), 1))
        painter.drawLine(int(cx - self._radius_outer), int(cy),
                         int(cx + self._radius_outer), int(cy))
        painter.drawLine(int(cx), int(cy - self._radius_outer),
                         int(cx), int(cy + self._radius_outer))

        # 小圆（可拖动）
        knob_x = cx + self._dx
        knob_y = cy + self._dy
        painter.setBrush(QBrush(QColor("#4a9fc8" if self._pressed else "#6fb8dd")))
        painter.setPen(QPen(QColor("#2f6f91"), 2))
        painter.drawEllipse(QPointF(knob_x, knob_y), self._radius_inner, self._radius_inner)

        # 中心小点标记
        painter.setBrush(QBrush(QColor("#888888")))
        painter.setPen(Qt.PenStyle.NoPen)
        painter.drawEllipse(QPointF(cx, cy), 4, 4)

    def mousePressEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            self._pressed = True
            self._update_knob(event.position())
            self._move_timer.start()

    def mouseMoveEvent(self, event):
        if self._pressed:
            self._update_knob(event.position())

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            self._pressed = False
            self._move_timer.stop()
            self._dx = 0.0
            self._dy = 0.0
            self.update()

    def _update_knob(self, pos):
        cx, cy = self.width() / 2, self.height() / 2
        dx = pos.x() - cx
        dy = pos.y() - cy
        max_r = self._radius_outer - self._radius_inner
        dist = (dx ** 2 + dy ** 2) ** 0.5
        if dist > max_r:
            dx = dx / dist * max_r
            dy = dy / dist * max_r
        self._dx = dx
        self._dy = dy
        self.update()


class ZFaderWidget(QWidget):
    """Z 轴拨杆 — 上下拖动控制 Z 速度，松开回中，越远越快"""

    def __init__(self, parent=None, max_speed=200):
        super().__init__(parent)
        self.setFixedSize(120, 320)
        self.setMouseTracking(True)

        self._max_speed = max_speed
        self._track_h = 260      # 滑道高度
        self._knob_h = 40        # 滑块高度
        self._knob_w = 80        # 滑块宽度
        self._deadzone = 8

        self._dy = 0.0           # 相对中心的偏移
        self._pressed = False

        self._move_timer = QTimer(self)
        self._move_timer.setInterval(MOVE_DETECT_MS)
        self._move_timer.timeout.connect(self._emit_move)

        self.on_move = None  # callable(direction, feedrate)  direction: +1 or -1

    def _emit_move(self):
        dist = abs(self._dy)
        if dist < self._deadzone:
            return
        max_dist = (self._track_h - self._knob_h) / 2
        ratio = min(dist / max_dist, 1.0)
        # speed = int((0.3 + ratio * 0.7) * self._max_speed / 10)
        speed = ratio * self._max_speed / (1000/MOVE_DETECT_MS)
        direction = 1 if self._dy < 0 else -1  # dy<0 → 向上
        if self.on_move:
            self.on_move(direction, speed)

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)
        cx = self.width() / 2

        # 滑道
        rect = QRectF(cx - 12, (self.height() - self._track_h) / 2, 24, self._track_h)
        painter.setBrush(QBrush(QColor("#2a2a2a")))
        painter.setPen(QPen(QColor("#666666"), 2))
        painter.drawRoundedRect(rect, 12, 12)

        # 中心刻度线
        mid_y = self.height() / 2
        painter.setPen(QPen(QColor("#777777"), 2))
        painter.drawLine(int(cx - 20), int(mid_y), int(cx + 20), int(mid_y))

        # 滑块
        knob_center_y = mid_y + self._dy
        knob_y = knob_center_y - self._knob_h / 2
        knob_rect = QRectF(cx - self._knob_w / 2, knob_y, self._knob_w, self._knob_h)

        color = "#4a9fc8" if self._pressed else "#6fb8dd"
        painter.setBrush(QBrush(QColor(color)))
        painter.setPen(QPen(QColor("#2f6f91"), 2))
        painter.drawRoundedRect(knob_rect, 10, 10)

        # Z 标签
        painter.setPen(QPen(QColor("#a0a0a0"), 1))
        font = QFont("sans-serif", 14, QFont.Weight.Bold)
        painter.setFont(font)
        painter.drawText(knob_rect, Qt.AlignmentFlag.AlignCenter, "Z")

    def mousePressEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            self._pressed = True
            self._update_knob(event.position().y())
            self._move_timer.start()

    def mouseMoveEvent(self, event):
        if self._pressed:
            self._update_knob(event.position().y())

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            self._pressed = False
            self._move_timer.stop()
            self._dy = 0.0
            self.update()

    def _update_knob(self, py):
        mid_y = self.height() / 2
        max_d = (self._track_h - self._knob_h) / 2
        dy = py - mid_y
        dy = max(-max_d, min(max_d, dy))
        self._dy = dy
        self.update()


class ControlPage(QWidget):
    def __init__(self, api_client, parent=None):
        super().__init__(parent)
        self.api_client = api_client
        self.config_parser = ConfigParse()
        self.config_parser.config_changed.connect(self._on_config_changed)
        self._load_limits()
        self._load_speeds()

        # 当前坐标（本地跟踪）
        self.pos_x = 0.0
        self.pos_y = 0.0
        self.pos_z = 0.0
        self._is_printing = False
        self._homed = False        # 是否已轴回零
        self._motor_on = True      # 电机是否已使能（默认True，关电机后置False）

        # 归零后的停留位置
        hp = self.config_parser.home_positions or {}
        self._home_x = hp.get("x", 0.0)
        self._home_y = hp.get("y", 0.0)
        self._home_z = hp.get("z", 0.0)

        # 悬浮键盘
        self._keyboard = FloatingKeyboard()
        self._keyboard_attached = False

        self.init_ui()
        self._sync_inputs()
        self._apply_state()
        self._start_status_poll()

    def _load_speeds(self):
        ms = self.config_parser.move_max_speed or {}
        self.move_speed_xy = ms.get("xy", 3000)
        self.move_speed_z = ms.get("z", 200)

    def _start_status_poll(self):
        self._status_timer = QTimer(self)
        self._status_timer.timeout.connect(self._poll_status)
        self._status_timer.start(2000)

    def _poll_status(self):
        """定时轮询打印机状态，更新按钮启用状态和坐标"""
        try:
            data = self.api_client.get_status()
            flags = data.get("status", {}).get("state", {}).get("flags", {})
            printing = flags.get("printing", False)
            paused = flags.get("paused", False)
            self._is_printing = printing or paused
        except Exception:
            self._is_printing = False

        self._update_buttons()

    def _load_limits(self):
        ma = self.config_parser.move_axis_area or {}
        self.x_min = ma.get("x_min", 0)
        self.x_max = ma.get("x_max", 300)
        self.y_min = ma.get("y_min", 0)
        self.y_max = ma.get("y_max", 300)
        self.z_min = ma.get("z_min", 0)
        self.z_max = ma.get("z_max", 300)

    def _on_config_changed(self, config_instance):
        self._load_limits()
        self._load_speeds()
        print(f"z-max-s:{self.move_speed_z}")

    # ── 状态管理 ──────────────────────────────────────────

    def _is_control_enabled(self):
        """摇杆/拨杆/坐标输入是否可用：已回零 + 电机已使能 + 非打印中"""
        return self._homed and self._motor_on and not self._is_printing

    def _apply_state(self):
        """根据回零/电机状态同步所有控件"""
        enabled = self._is_control_enabled()
        self.joystick.setEnabled(enabled)
        self.z_fader.setEnabled(enabled)
        for inp in (self.input_x, self.input_y, self.input_z):
            inp.setEnabled(enabled)
            if not enabled:
                inp.setText("---")
        if enabled:
            self._sync_inputs()

    def _sync_inputs(self):
        """将 pos 值同步到输入框"""
        if self._is_control_enabled():
            self.input_x.setText(f"{self.pos_x:.3f}")
            self.input_y.setText(f"{self.pos_y:.3f}")
            self.input_z.setText(f"{self.pos_z:.3f}")

    def _on_coord_changed(self):
        """输入框手动输入触发运动"""
        if not self._is_control_enabled():
            return
        try:
            tx = float(self.input_x.text())
            ty = float(self.input_y.text())
            tz = float(self.input_z.text())
        except ValueError:
            return
        tx = max(self.x_min, min(self.x_max, tx))
        ty = max(self.y_min, min(self.y_max, ty))
        tz = max(self.z_min, min(self.z_max, tz))
        gcode = f"G1 X{tx:.3f} Y{ty:.3f} Z{tz:.3f} F3000"
        self.api_client.send_gcode(gcode)
        self.pos_x, self.pos_y, self.pos_z = tx, ty, tz
        self._sync_inputs()

    def _update_buttons(self):
        printing = self._is_printing
        self.btn_pause.setEnabled(printing)
        self.btn_stop.setEnabled(printing)
        idle = not printing
        self.btn_home.setEnabled(idle)
        self.btn_level.setEnabled(idle)
        self.btn_motor_off.setEnabled(idle)
        self._apply_state()

    # ── GCode 发送 ──────────────────────────────────────────

    def _send_move(self, x=None, y=None, z=None, feedrate=None):
        if not self._is_control_enabled():
            return
        target_x = self.pos_x if x is None else x
        target_y = self.pos_y if y is None else y
        target_z = self.pos_z if z is None else z
        target_x = max(self.x_min, min(self.x_max, target_x))
        target_y = max(self.y_min, min(self.y_max, target_y))
        target_z = max(self.z_min, min(self.z_max, target_z))
        f = feedrate or 3000
        gcode = f"G1 X{target_x:.3f} Y{target_y:.3f} Z{target_z:.3f} F{f}"
        self.api_client.send_gcode(gcode)
        self.pos_x, self.pos_y, self.pos_z = target_x, target_y, target_z
        self._sync_inputs()

    # ── 摇杆/拨杆回调 ──

    def _on_joystick_move(self, nx, ny, speed):
        if not self._is_control_enabled():
            return
        step = 5.0
        dx = nx * step
        dy = ny * step
        tx = max(self.x_min, min(self.x_max, self.pos_x + dx))
        ty = max(self.y_min, min(self.y_max, self.pos_y + dy))
        gcode = f"G1 X{tx:.1f} Y{ty:.1f} F{speed}"
        self.api_client.send_gcode(gcode)
        self.pos_x, self.pos_y = tx, ty
        self._sync_inputs()

    def _on_fader_move(self, direction, speed):
        if not self._is_control_enabled():
            return
        print(f"d:{direction} s:{speed}")
        step = speed * MOVE_DETECT_MS / 1000
        tz = self.pos_z + direction * step
        tz = max(self.z_min, min(self.z_max, tz))
        gcode = f"G1 Z{tz:.3f} F{speed}"
        self.api_client.send_gcode(gcode)
        self.pos_z = tz
        self._sync_inputs()

    # ── 指令按钮 ──

    def _cmd_pause(self):
        self.api_client.pause_print()

    def _cmd_stop(self):
        self.api_client.stop_print()

    def _cmd_home(self):
        self.api_client.home_axes(["x", "y", "z"])
        self.pos_x = self._home_x
        self.pos_y = self._home_y
        self.pos_z = self._home_z
        self._homed = True
        self._motor_on = True
        self._sync_inputs()
        self._apply_state()

    def _cmd_level(self):
        self.api_client.auto_leveling()

    def _cmd_motor_off(self):
        self.api_client.off_motors()
        self._motor_on = False
        self._apply_state()

    # ── 悬浮键盘 ─────────────────────────────────────────────

    def _attach_keyboard(self, widget):
        """将悬浮键盘绑定到指定输入框并显示"""
        self._keyboard.attach(widget)
        self._keyboard.show_below(widget)
        self._keyboard_attached = True

    def _dismiss_keyboard(self):
        """关闭悬浮键盘"""
        self._keyboard.hide()
        self._keyboard.detach()
        self._keyboard_attached = False

    def _on_input_focus_in(self, widget):
        """输入框获得焦点时的处理"""
        if self._keyboard_attached:
            self._keyboard.attach(widget)
            self._keyboard.show_below(widget)
        else:
            self._attach_keyboard(widget)

    def eventFilter(self, obj, event):
        if event.type() == QEvent.Type.FocusIn:
            if obj in (self.input_x, self.input_y, self.input_z):
                self._on_input_focus_in(obj)
            elif self._keyboard_attached and not isinstance(obj, QLineEdit):
                self._dismiss_keyboard()
        elif event.type() == QEvent.Type.FocusOut:
            if obj in (self.input_x, self.input_y, self.input_z):
                QTimer.singleShot(100, self._check_dismiss_keyboard)
        return super().eventFilter(obj, event)

    def _check_dismiss_keyboard(self):
        """检查当前焦点是否还在坐标输入框上，不在则关闭键盘"""
        w = self.focusWidget()
        if w not in (self.input_x, self.input_y, self.input_z):
            self._dismiss_keyboard()

    # ── UI 构建 ──────────────────────────────────────────────

    def init_ui(self):
        self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)

        main_layout = QHBoxLayout(self)
        main_layout.setContentsMargins(14, 14, 14, 14)
        main_layout.setSpacing(14)

        # =========================== 左栏 ===========================
        left_panel = QFrame()
        left_panel.setStyleSheet("background-color: #3f3f3f; border-radius: 10px;")
        left_panel.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
        left_layout = QVBoxLayout(left_panel)
        left_layout.setContentsMargins(16, 14, 16, 14)
        left_layout.setSpacing(8)

        left_title = QLabel("控制")
        left_title.setAlignment(Qt.AlignmentFlag.AlignCenter)
        left_title.setStyleSheet("color: #efefef; font-size: 22px; font-weight: 700;")
        left_layout.addWidget(left_title)

        btn_style = """
        QPushButton {
            min-height: 50px;
            font-size: 18px;
            font-weight: 600;
            color: #f8f8f8;
            background-color: #555555;
            border: 2px solid #888888;
            border-radius: 8px;
            padding: 4px 12px;
        }
        QPushButton:hover {
            background-color: #636363;
            border-color: #aaaaaa;
        }
        QPushButton:pressed {
            background-color: #3d3d3d;
            border-color: #5a9fcf;
        }
        QPushButton:disabled {
            color: #606060;
            background-color: #3a3a3a;
            border-color: #505050;
        }
        """

        grid_btns = QGridLayout()
        grid_btns.setSpacing(8)

        self.btn_pause = QPushButton("⏸ 暂停打印")
        self.btn_pause.setStyleSheet(btn_style)
        self.btn_pause.clicked.connect(self._cmd_pause)
        grid_btns.addWidget(self.btn_pause, 0, 0)

        self.btn_stop = QPushButton("⏹ 停止打印")
        self.btn_stop.setStyleSheet(btn_style)
        self.btn_stop.clicked.connect(self._cmd_stop)
        grid_btns.addWidget(self.btn_stop, 0, 1)

        self.btn_home = QPushButton("⌂ 轴回零")
        self.btn_home.setStyleSheet(btn_style)
        self.btn_home.clicked.connect(self._cmd_home)
        grid_btns.addWidget(self.btn_home, 1, 0)

        self.btn_level = QPushButton("◉ 自动调平")
        self.btn_level.setStyleSheet(btn_style)
        self.btn_level.clicked.connect(self._cmd_level)
        grid_btns.addWidget(self.btn_level, 1, 1)

        self.btn_motor_off = QPushButton("⏻ 关电机")
        self.btn_motor_off.setStyleSheet(btn_style)
        self.btn_motor_off.clicked.connect(self._cmd_motor_off)
        grid_btns.addWidget(self.btn_motor_off, 2, 0, 1, 2)

        left_layout.addLayout(grid_btns)
        main_layout.addWidget(left_panel, 2)

        # =========================== 右栏 ===========================
        right_panel = QFrame()
        right_panel.setStyleSheet("background-color: #3f3f3f; border-radius: 10px;")
        right_panel.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
        right_layout = QVBoxLayout(right_panel)
        right_layout.setContentsMargins(16, 14, 16, 14)
        right_layout.setSpacing(10)

        # ── 坐标输入 ──
        coord_row = QHBoxLayout()
        coord_row.setSpacing(12)
        coord_row.setAlignment(Qt.AlignmentFlag.AlignCenter)

        input_style = """
        QLineEdit {
            min-width: 80px;
            max-width: 120px;
            min-height: 44px;
            font-size: 24px;
            font-weight: 700;
            color: #e0e0e0;
            background-color: #2a2a2a;
            border: 2px solid #646464;
            border-radius: 8px;
            padding: 4px 10px;
            text-align: center;
        }
        QLineEdit:focus {
            border-color: #5a9fcf;
        }
        QLineEdit:disabled {
            color: #606060;
            background-color: #222222;
            border-color: #444444;
        }
        """

        for axis, val in [("X", 0.0), ("Y", 0.0), ("Z", 0.0)]:
            lbl = QLabel(f"{axis}:")
            lbl.setStyleSheet("color: #d0d0d0; font-size: 24px; font-weight: 700;")
            coord_row.addWidget(lbl)

            inp = QLineEdit(f"{val:.1f}")
            inp.setStyleSheet(input_style)
            inp.setAlignment(Qt.AlignmentFlag.AlignCenter)
            inp.setValidator(QDoubleValidator(-9999, 9999, 1))
            inp.returnPressed.connect(self._on_coord_changed)
            inp.installEventFilter(self)
            setattr(self, f"input_{axis.lower()}", inp)
            coord_row.addWidget(inp)

        right_layout.addLayout(coord_row)

        # ── 操作器 ──
        manip_row = QHBoxLayout()
        manip_row.setSpacing(14)
        manip_row.setAlignment(Qt.AlignmentFlag.AlignCenter)

        self.joystick = JoystickWidget(max_speed=self.move_speed_xy)
        self.joystick.on_move = self._on_joystick_move
        manip_row.addWidget(self.joystick)

        self.z_fader = ZFaderWidget(max_speed=self.move_speed_z)
        self.z_fader.on_move = self._on_fader_move
        manip_row.addWidget(self.z_fader)

        right_layout.addLayout(manip_row)

        main_layout.addWidget(right_panel, 3)
        self._update_buttons()