from qtsymbols import *
import windows, NativeUtils, gobject
from myutils.config import globalconfig
from myutils.hwnd import safepixmap
from gui.dynalang import LAction
from traceback import print_exc


class SideGrip(QWidget):
    def __init__(self, parent, edge):
        QWidget.__init__(self, parent)
        if edge == Qt.Edge.LeftEdge:
            self.setCursor(Qt.CursorShape.SizeHorCursor)
            self.resizeFunc = self.resizeLeft
        elif edge == Qt.Edge.TopEdge:
            self.setCursor(Qt.CursorShape.SizeVerCursor)
            self.resizeFunc = self.resizeTop
        elif edge == Qt.Edge.RightEdge:
            self.setCursor(Qt.CursorShape.SizeHorCursor)
            self.resizeFunc = self.resizeRight
        else:
            self.setCursor(Qt.CursorShape.SizeVerCursor)
            self.resizeFunc = self.resizeBottom
        self.mousePos = None

    def resizeLeft(self, delta):
        window = self.window()
        width = max(window.minimumWidth(), window.width() - delta.x())
        geo = window.geometry()
        geo.setLeft(geo.right() - width)
        window.setGeometry(geo)

    def resizeTop(self, delta):
        window = self.window()
        height = max(window.minimumHeight(), window.height() - delta.y())
        geo = window.geometry()
        geo.setTop(geo.bottom() - height)
        window.setGeometry(geo)

    def resizeRight(self, delta):
        window = self.window()
        width = max(window.minimumWidth(), window.width() + delta.x())
        window.resize(width, window.height())

    def resizeBottom(self, delta):
        window = self.window()
        height = max(window.minimumHeight(), window.height() + delta.y())
        window.resize(window.width(), height)

    def mousePressEvent(self, event: QMouseEvent):
        if event.button() == Qt.MouseButton.LeftButton:
            self.mousePos = event.pos()

    def mouseMoveEvent(self, event: QMouseEvent):
        if self.mousePos is not None:
            delta = event.pos() - self.mousePos
            self.resizeFunc(delta)

    def mouseReleaseEvent(self, _):
        self.mousePos = None


class Mainw(QMainWindow):
    _gripSize = 8

    def __init__(self, x):
        QMainWindow.__init__(self, x)

        self.setWindowFlags(Qt.WindowType.FramelessWindowHint | self.windowFlags())

        self.sideGrips = [
            SideGrip(self, Qt.Edge.LeftEdge),
            SideGrip(self, Qt.Edge.TopEdge),
            SideGrip(self, Qt.Edge.RightEdge),
            SideGrip(self, Qt.Edge.BottomEdge),
        ]
        # corner grips should be "on top" of everything, otherwise the side grips
        # will take precedence on mouse events, so we are adding them *after*;
        # alternatively, widget.raise_() can be used
        self.cornerGrips = [QSizeGrip(self) for i in range(4)]
        for s in self.cornerGrips:
            s.setStyleSheet("background-color: transparent;")

    @property
    def gripSize(self):
        return self._gripSize

    def setGripSize(self, size):
        if size == self._gripSize:
            return
        self._gripSize = max(2, size)
        self.updateGrips()

    def updateGrips(self):
        self.setContentsMargins(*[self.gripSize] * 4)

        outRect = self.rect()
        # an "inner" rect used for reference to set the geometries of size grips
        inRect = outRect.adjusted(
            self.gripSize, self.gripSize, -self.gripSize, -self.gripSize
        )

        # top left
        self.cornerGrips[0].setGeometry(QRect(outRect.topLeft(), inRect.topLeft()))
        # top right
        self.cornerGrips[1].setGeometry(
            QRect(outRect.topRight(), inRect.topRight()).normalized()
        )
        # bottom right
        self.cornerGrips[2].setGeometry(
            QRect(inRect.bottomRight(), outRect.bottomRight())
        )
        # bottom left
        self.cornerGrips[3].setGeometry(
            QRect(outRect.bottomLeft(), inRect.bottomLeft()).normalized()
        )

        # left edge
        self.sideGrips[0].setGeometry(0, inRect.top(), self.gripSize, inRect.height())
        # top edge
        self.sideGrips[1].setGeometry(inRect.left(), 0, inRect.width(), self.gripSize)
        # right edge
        self.sideGrips[2].setGeometry(
            inRect.left() + inRect.width(), inRect.top(), self.gripSize, inRect.height()
        )
        # bottom edge
        self.sideGrips[3].setGeometry(
            self.gripSize, inRect.top() + inRect.height(), inRect.width(), self.gripSize
        )

    def resizeEvent(self, event):
        QMainWindow.resizeEvent(self, event)
        self.updateGrips()


class rangeadjust(Mainw):
    closesignal = pyqtSignal()
    traceoffsetsignal = pyqtSignal(QPoint)

    @property
    def isfocus(self):
        return self.__isfocus

    @isfocus.setter
    def isfocus(self, f):
        def cleanother():
            for r in self.ranges:
                range_ui: "rangeadjust" = r.range_ui
                if range_ui != self:
                    if range_ui.__isfocus:
                        range_ui.__isfocus = False
                        range_ui.setstyle()

        if sum(not (r.range_ui._rect is None) for r in self.ranges) > 1:
            if f:
                cleanother()
                self.__isfocus = True
            else:
                self.__isfocus = False
        else:
            cleanother()
            self.__isfocus = False
        self.setstyle()

    def mouseDoubleClickEvent(self, a0):
        self.isfocus = not self.isfocus
        gobject.base.translation_ui.startTranslater()
        return super().mouseDoubleClickEvent(a0)

    def starttrace(self, pos):
        self.tracepos = self.geometry().topLeft()
        self.traceposstart = pos

    def traceoffset(self, curr: QPoint):
        hwnd = gobject.base.hwnd
        if not hwnd:
            self.tracepos = QPoint()
            return
        if windows.MonitorFromWindow(hwnd) != windows.MonitorFromWindow(
            int(self.winId())
        ):
            self.tracepos = QPoint()
            return
        keystate = windows.GetKeyState(windows.VK_LBUTTON)
        if keystate < 0 and windows.GetForegroundWindow() == int(self.winId()):
            self.tracepos = QPoint()
            return
        if self._isTracking:
            self.tracepos = QPoint()
            return
        _geo = self.geometry()
        if self.tracepos.isNull():
            self.tracepos = _geo.topLeft()
            self.traceposstart = curr
        target = self.tracepos + (curr - self.traceposstart) * self.devicePixelRatioF()
        self.setGeometry(
            target.x(),
            target.y(),
            _geo.width(),
            _geo.height(),
        )

    def rect(self):
        geo = self.geometry()
        return QRectF(
            0,
            0,
            geo.width() / self.devicePixelRatioF(),
            geo.height() / self.devicePixelRatioF(),
        ).toRect()

    def __init__(self, parent, ranges):
        super().__init__(parent)
        self.__isfocus = False
        self.ranges: list = ranges
        self.traceoffsetsignal.connect(self.traceoffset)
        self.label = QLabel(self)
        self.setstyle()
        self.closesignal.connect(self.close)
        self.tracepos = QPoint()
        self.drag_label = QLabel(self)
        self.drag_label.setGeometry(0, 0, 4000, 2000)
        self._isTracking = False
        self._rect = None
        self.setWindowFlags(
            Qt.WindowType.WindowStaysOnTopHint
            | Qt.WindowType.FramelessWindowHint
            | Qt.WindowType.Tool
        )
        self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
        self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
        self.customContextMenuRequested.connect(self.showmenu)
        for s in self.cornerGrips:
            s.raise_()

    def showmenu(self, _):
        menu = QMenu(self)
        close = LAction("关闭", menu)
        mousetransp = LAction("鼠标穿透窗口", menu)
        menu.addAction(mousetransp)
        menu.addAction(close)
        action = menu.exec(QCursor.pos())
        if action == mousetransp:
            windows.MouseTrans.set(self.winId())
        elif action == close:
            self._rect = None
            self.isfocus = False
            self.close()

    def setstyle(self):
        self.label.setStyleSheet(
            " border:%spx solid %s; background-color: rgba(0,0,0, %s); border-radius:0;"
            % (
                globalconfig.get("ocrrangewidth", 2),
                "red" if self.isfocus else globalconfig["ocrrangecolor"],
                1 / 255,
            )
        )

    def mouseMoveEvent(self, e: QMouseEvent):
        if self._isTracking:
            self._endPos = e.pos() - self._startPos
            _geo = self.geometry()
            _geo.translate(self._endPos)
            self.setGeometry(*_geo.getRect())

    def mousePressEvent(self, e: QMouseEvent):
        if e.button() == Qt.MouseButton.LeftButton:
            self._isTracking = True
            self._startPos = QPoint(e.pos().x(), e.pos().y())

    def mouseReleaseEvent(self, e: QMouseEvent):
        if e.button() == Qt.MouseButton.LeftButton:
            self._isTracking = False
            self._startPos = None
            self._endPos = None

    def rectoffset(self, rect: QRect):
        r = self.devicePixelRatioF()
        r = int(globalconfig.get("ocrrangewidth", 2) * r)
        _ = [(rect.left() + r, rect.top() + r), (rect.right() - r, rect.bottom() - r)]
        return _

    def setGeometry(self, x, y, w, h):
        windows.MoveWindow(int(self.winId()), x, y, w, h, True)

    def geometry(self):
        rect = windows.GetWindowRect(int(self.winId()))
        return QRect(rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1])

    def moveEvent(self, _):
        if self._rect:
            self._rect = self.rectoffset(self.geometry())

    def enterEvent(self, _):
        self.drag_label.setStyleSheet("background-color:rgba(0,0,0, 0.1)")

    def leaveEvent(self, _):
        self.drag_label.setStyleSheet("background-color:none")

    def resizeEvent(self, a0):

        self.label.setGeometry(0, 0, self.width(), self.height())
        if self._rect:
            self._rect = self.rectoffset(self.geometry())
        super().resizeEvent(a0)

    def getrect(self):
        return self._rect

    def setrect(self, rect, show=True):
        self.tracepos = QPoint()
        if rect:
            (x1, y1), (x2, y2) = rect
            if show:
                self.show()
            r = self.devicePixelRatioF()
            self.setGeometry(
                x1 - int(globalconfig.get("ocrrangewidth", 2) * r),
                y1 - int(globalconfig.get("ocrrangewidth", 2) * r),
                x2 - x1 + int(2 * globalconfig.get("ocrrangewidth", 2) * r),
                y2 - y1 + int(2 * globalconfig.get("ocrrangewidth", 2) * r),
            )
        self._rect = rect
        # 由于使用movewindow而非qt函数，导致内部执行绪有问题。


def rangeselct_function(callback, parent: QWidget = None, hideshow=False):
    p = gobject.base.translation_ui
    if hideshow:
        currpos = p.pos()
        _save = {}
        # hide会有隐藏动画残影
        if parent:
            currpos2 = parent.pos()
            parent.move(-9999, -9999)
        p.move(-9999, -9999)
        try:
            gobject.base.textsource.pause_recognition()
            for _ in gobject.base.textsource.ranges:
                _save[_] = _.range_ui.getrect()
                _.range_ui.setrect(((-9999, -9999), (-9999, -9999)), show=False)
        except:
            pass

    def reset():
        if not hideshow:
            return
        gobject.base.translation_ui.move(currpos)
        if parent:
            parent.move(currpos2)
        try:
            for _ in gobject.base.textsource.ranges:
                _.range_ui.setrect(_save[_], show=False)
            gobject.base.textsource.resume_recognition()
        except:
            pass

    p = p.winid if p.isVisible() else None
    color = QColor(globalconfig["ocrrangecolor"])

    called = []

    def __cb(x1, y1, x2, y2, xoff, yoff, ptr, size):
        x1, x2 = min(x1, x2), max(x1, x2)
        y1, y2 = min(y1, y2), max(y1, y2)
        pix = safepixmap(ptr[:size]).copy(x1, y1, x2 - x1, y2 - y1).toImage()
        reset()
        callback(((x1 + xoff, y1 + yoff), (x2 + xoff, y2 + yoff)), pix)
        called.append(0)

    cb = NativeUtils.CreateSelectRangeWindow_CB(__cb)
    NativeUtils.CreateSelectRangeWindow(
        p,
        globalconfig.get("ocrselectalpha", 0.3),
        color.red(),
        color.green(),
        color.blue(),
        globalconfig.get("ocrrangewidth", 2),
        cb,
    )
    if not called:
        reset()
        callback(((0, 0), (0, 0)), None)
