import os
import sys


from PySide6.QtCore import QObject, Qt, QThread, Signal, Slot, qVersion
from PySide6.QtGui import QGuiApplication

from shiboken6 import Shiboken


class ChildObject(QObject):
    pass


class EchoObject(QObject):

    echo = Signal(str)

    def __init__(self):
        super().__init__()

    @Slot(str)
    def doEcho(self, val):
        st = self.thread()
        ct = QThread.currentThread()
        print(f'\nEchoObject.doEcho val={val}:\n  self.thread() :',
              st, "\n  current thread:", ct)
        self.echo.emit(val)


class SenderObject(QObject):
    send = Signal(str)

    def __init__(self):
        super().__init__()

    def sendMessage(self, msg):
        st = self.thread()
        ct = QThread.currentThread()
        print(f"\nSenderObject.sendMessage({msg})\n  self.thread() :",
              st, "\n  current thread:", ct)
        self.send.emit(msg)


class ReceiverObject(QObject):
    quit = Signal()

    def __init__(self):
        super().__init__()
        ct = QThread.currentThread()
        print('\nReceiverObject.__init__()\n  current thread:', ct)
        self.child = None

    @Slot(str)
    def onMessage(self, msg):
        st = self.thread()
        ct = QThread.currentThread()
        print(f'\nReceiverObject.onMessage({msg})\n  self.thread() :',
              st, "\n  current thread:", ct)
        self.child = ChildObject(self)
        self.quit.emit()


class DerivedReceiverObject(ReceiverObject):
    @Slot(str)
    def onMessage(self, msg):
        st = self.thread()
        ct = QThread.currentThread()
        print(f'\nDerivedReceiverObject.onMessage({msg})\n  self.thread() :',
              st, "\n  current thread:", ct)
        ReceiverObject.onMessage(self, msg + " modified")


if __name__ == "__main__":
    os.environ['QT_LOGGING_RULES'] = "qt.pyside.libpyside.warning=true"
    application = QGuiApplication(sys.argv)
    USE_DERIVED = "-d" not in sys.argv

    print(application.platformName(), qVersion(), '\n')

    gui_thread = QThread.currentThread()
    print(f"{gui_thread=}")
    # print(Shiboken.dump(gui_thread))

    other_thread = QThread()
    other_thread.setObjectName("other_thread")
    print(f"{other_thread=}")
    # print(Shiboken.dump(other_thread))
    other_thread.start()

    sender = SenderObject()

    if USE_DERIVED:
        receiver = DerivedReceiverObject()
        receiver.setObjectName("DerivedReceiver")
    else:
        receiver = ReceiverObject()
        receiver.setObjectName("Receiver")

    echo = EchoObject()
    echo.setObjectName("Echo")
    echo.moveToThread(other_thread)

    sender.send.connect(echo.doEcho, Qt.ConnectionType.QueuedConnection)
    echo.echo.connect(receiver.onMessage, Qt.ConnectionType.QueuedConnection)

    def cleanup() -> None:
        other_thread.quit()
        other_thread.wait()
        application.quit()
    receiver.quit.connect(cleanup, Qt.ConnectionType.QueuedConnection)

    sender.sendMessage("test")

    application.exec()
