from PyQt5.QtWidgets import QMainWindow, QLabel, QPushButton, QFileDialog, QFrame
from PyQt5.QtCore import QEvent, Qt
from PyQt5.QtGui import QPixmap
import numpy as np

from .custom_threading import Counter


class QtVizWindow(QMainWindow):
    """
    Qt visualization window for the sfctools World
    """

    def __init__(self, parent, width, height, add_navigation=False):
        super().__init__()
        self.parent = parent  # parent visuals are WorldVisuals
        self.setWindowTitle("sfctools Visualization")
        self.setGeometry(0, 0, width, height)

        self.frame = QLabel(self)
        self.frame.setGeometry(0, 0, width, height)
        self.frame.setFrameShadow(QFrame.Sunken)
        self.frame.setMouseTracking(True)
        self.frame.installEventFilter(self)

        self.pixmap = None
        self.dpi = None
        self.paused = False
        self.scale = 2.0
        self.last_pos = (0, 0)

        self.count_rot_xy = Counter(name="rot-xy")
        self.count_rot_z = Counter(name="rot-z")
        self.count_rot_xy.start_counting()
        self.count_rot_z.start_counting()

        if add_navigation:
            self._create_navigation_buttons(width)

    def _create_navigation_buttons(self, w):
        """
        Create and position navigation and control buttons
        """
        # Rotation
        self.btnxy1 = QPushButton("↶", self)
        self.btnxy2 = QPushButton("↷", self)
        self.btnz1 = QPushButton("↺", self)
        self.btnz2 = QPushButton("↻", self)

        # Panning
        self.btnmvx_dn = QPushButton("⇦", self)
        self.btnmvx_up = QPushButton("⇨", self)
        self.btnmvy_up = QPushButton("⇧", self)
        self.btnmvy_dn = QPushButton("⇩", self)

        # Control
        self.pauseButton = QPushButton("▶|", self)
        self.saveButton = QPushButton("Save", self)

        # Style
        print("bgcolor", self.parent.bg_color)
        btn_style = f"QPushButton{{font-size: 18pt;}} QMainWindow{{background-color: '{self.parent.bg_color}';}}"
        for btn in [self.btnxy1, self.btnxy2, self.btnz1, self.btnz2,
                    self.btnmvx_up, self.btnmvx_dn, self.btnmvy_up, self.btnmvy_dn,
                    self.pauseButton, self.saveButton]:
            btn.setStyleSheet(btn_style)

        # Button actions
        self.pauseButton.pressed.connect(
            lambda: setattr(self, "paused", not self.paused))

        self.btnxy1.pressed.connect(lambda: self.start_rotate_xy(-1))
        self.btnxy1.released.connect(self.stop_rotate_xy)

        self.btnxy2.pressed.connect(lambda: self.start_rotate_xy(1))
        self.btnxy2.released.connect(self.stop_rotate_xy)

        self.btnz1.pressed.connect(lambda: self.start_rotate_z(-1))
        self.btnz1.released.connect(self.stop_rotate_z)

        self.btnz2.pressed.connect(lambda: self.start_rotate_z(1))
        self.btnz2.released.connect(self.stop_rotate_z)

        self.btnmvx_dn.released.connect(lambda: self.shift(-3, 0))
        self.btnmvx_up.released.connect(lambda: self.shift(+3, 0))
        self.btnmvy_up.released.connect(lambda: self.shift(0, -3))
        self.btnmvy_dn.released.connect(lambda: self.shift(0, +3))

        self.saveButton.pressed.connect(self.start_pdf_saving)

        # Positioning
        self.btnxy1.move(w - 210, 50)
        self.btnxy2.move(w - 110, 50)
        self.btnz1.move(w - 210, 80)
        self.btnz2.move(w - 110, 80)
        self.saveButton.move(w - 110, 2)

        self.btnmvy_up.move(w - 160, 120)
        self.btnmvx_dn.move(w - 210, 150)
        self.btnmvx_up.move(w - 110, 150)
        self.btnmvy_dn.move(w - 160, 180)

        self.pauseButton.move(w - 160, 220)

    def start_pdf_saving(self):
        """Prompt user to save visualization as PDF"""
        file_path, _ = QFileDialog.getSaveFileName(
            self, "Save Screenshot as PDF", "", "PDF Files (*.pdf);;All Files (*)"
        )
        if file_path:
            self.parent.pdf_filepath = file_path
            self.parent.set_engine("Pdf")

    def shift(self, dx, dy):
        self.parent.dX += dx
        self.parent.dY += dy

    def start_rotate_xy(self, speed):
        self.count_rot_xy.set_speed(speed)

    def stop_rotate_xy(self):
        self.count_rot_xy.set_speed(0)

    def start_rotate_z(self, speed):
        self.count_rot_z.set_speed(speed)

    def stop_rotate_z(self):
        self.count_rot_z.set_speed(0)

    def eventFilter(self, source, event):
        if event.type() == QEvent.MouseButtonPress:
            self.last_pos = (event.pos().x(), event.pos().y())

        elif event.type() == QEvent.MouseMove:
            if event.buttons() == Qt.NoButton:
                self._handle_hover(event.pos().x(), event.pos().y())
            else:
                self._handle_drag(event.pos().x(), event.pos().y())

        elif event.type() == QEvent.MouseButtonRelease:
            self.stop_rotate_xy()
            self.stop_rotate_z()
            self.last_pos = (event.pos().x(), event.pos().y())

        elif event.type() == QEvent.Wheel:
            delta = event.angleDelta().y()
            self.scale += 0.1 if delta > 0 else -0.1
            self.scale = np.clip(self.scale, 0.1, 10.0)

        return super().eventFilter(source, event)

    def _handle_hover(self, x, y):
        if not self.parent.handle_hover:
            return
        selection = None
        for obj in self.parent.object_buffer:
            ox, oy, _ = self.parent.get_scaled_obj_coord(obj)
            ox += 0.25 * obj.size[0]
            oy += 0.25 * obj.size[1]
            if abs(x - ox) < 7 and abs(y - oy) < 7:
                obj.hover = True
                selection = obj
            else:
                obj.hover = False
        self.parent.selection = selection

    def _handle_drag(self, x, y):
        s = 2 * np.pi * 0.01
        dx = x - self.last_pos[0]
        dy = y - self.last_pos[1]

        self.count_rot_xy.value += np.arctan2(dy * s, 1)
        self.count_rot_z.value += np.arctan2(dx * s, 1)

        print(
            f"rotxy: {self.count_rot_xy.value:.02f}, rotz: {self.count_rot_z.value:.02f}")

        self.last_pos = (x, y)

    def closeEvent(self, event):
        print("Closing visualization window...")
        self.count_rot_xy.stop_counting()
        self.count_rot_z.stop_counting()
        self.parent.running = False
        self.is_open = False
        super().closeEvent(event)
