import re
import sys

import matplotlib
from matplotlib.backend_bases import MouseButton
# Make sure that we are using QT5
matplotlib.use('Qt5Agg')
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure

from PySide2 import QtCore, QtGui
from PySide2.QtCore import QTimer, Qt, QObject
from PySide2.QtWidgets import QSizePolicy, QMainWindow, QApplication, QVBoxLayout, QWidget

from numpy import arange, sin, pi
from src.gui.AnimatedHoverMenu import SlideHoverMenuWithMarkers


class MyMplCanvas(FigureCanvas, QObject):
    """Ultimately, this is a QWidget (as well as a FigureCanvasAgg, etc.)."""

    def __init__(self, parent=None, width=5, height=4, dpi=100):
        fig = Figure(figsize=(width, height), dpi=dpi)
        self.fig = fig
        self.axes = fig.add_subplot(111)

        self.compute_initial_figure()

        FigureCanvas.__init__(self, fig)
        self.setParent(parent)

        FigureCanvas.setSizePolicy(self,
                                   QSizePolicy.Expanding,
                                   QSizePolicy.Expanding)
        FigureCanvas.updateGeometry(self)

        self.setFocusPolicy(Qt.StrongFocus)
        self.setFocus()

        self.mpl_connect('pick_event', self.on_picked)
        #self.mpl_connect('key_press_event', self.on_key_pressed)
        #self.mpl_connect('motion_notify_event', self.on_notify_motion)
        #self.mpl_connect('button_press_event', self.on_button_pressed)

        qApp.installEventFilter(self)
        #self.setEnabled(False)
        #self.setMouseTracking(False)
        self.pick_menu = SlideHoverMenuWithMarkers(parent=self)
        #self.tooltip_timer = QTimer(self, singleShot=True)

    def compute_initial_figure(self):
        val_count = 10000000
        end_val = 10
        t = arange(0.0, end_val, end_val/val_count)
        s1 = sin(2 * pi * t)
        s2 = sin(2 * pi * t + 1)
        self.axes.plot(t, s1, picker=5)
        self.axes.plot(t, s2, picker=5)

    # def on_notify_motion(self, event):
        # print("motion")
        # self.pick_tooltip.showText(
        #     QCursor.pos(),
        #     "motion",
        #     self,
        #     msecShowTime=100)

    def on_picked(self, event):
        QtGui.QGuiApplication.setOverrideCursor(QtGui.QCursor(Qt.WaitCursor))
        print(f"picked {event.artist.get_label()}")
        mouseevent = event.mouseevent
        if mouseevent.button == MouseButton.LEFT:
            thisline: matplotlib.lines.Line2D = event.artist

            xdata = thisline.get_xdata(orig=True)
            ydata = thisline.get_ydata(orig=True)

            # find coordinates of data point at about center of pick range
            mid_index = int(event.ind.mean())
            xdata_mid = xdata[mid_index]
            ydata_mid = ydata[mid_index]
            pos_mid_index = thisline.axes.transData.transform((xdata_mid, ydata_mid))
            # align hover position at line
            #pos = map_mpl_to_qt_glob(pos_mid_index)

            def map_mpl_data_to_qt_glob(coord: tuple) -> QtCore.QPoint:
                mpl_coord = thisline.axes.transData.transform(coord)
                return self.mapToGlobal(QtCore.QPoint(mpl_coord[0], self.fig.canvas.renderer.height - mpl_coord[1]))

            # find coordinates of data point nearest to cursor
            pos = QtGui.QCursor.pos()
            index_dist = [QtCore.QLineF(map_mpl_data_to_qt_glob((xdata[i], ydata[i])), pos).length() for i in event.ind]
            near_index = event.ind[index_dist.index(min(index_dist))]

            # get all data points within pick range
            #ind = event.ind
            #points = tuple(zip(xdata[ind], ydata[ind]))

            # get data at center of pick range
            #points = tuple(((xdata_mid, ydata_mid),))

            # get data of nearest point
            points = tuple(((xdata[near_index], ydata[near_index]),))

            # build text string
            line_name = thisline.get_label()
            if len(line_name) > 13:
                line_name = re.sub(r'^(.{6}).*(.{4})$', '\g<1>...\g<2>', line_name)  # cut middle part
            p_str = line_name + '\t'
            for x, y in points:
                p_str += f"{x:.2f} :  {y:.3f}\n"
            p_str = p_str[:-1]

            print("pick")
            self.pick_menu(pos, p_str, thisline, points)

        QtGui.QGuiApplication.restoreOverrideCursor()


class ApplicationWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.setAttribute(Qt.WA_DeleteOnClose)

        self.main_widget = QWidget(self)

        l = QVBoxLayout(self.main_widget)
        sc = MyMplCanvas(self.main_widget, width=5, height=4, dpi=100)
        l.addWidget(sc)

        self.main_widget.setFocus()
        self.setCentralWidget(self.main_widget)


qApp = QApplication(sys.argv)
aw = ApplicationWindow()
aw.show()
sys.exit(qApp.exec_())