#!D:/IDE/anaconda3/envs/Microscope_Scan python
# -*- coding: UTF-8 -*-
"""
@FileName：WebServerImpl.py
@Description：
@Author：XSH
@Time：2025/11/12 10:04
@Department：研发部
@Copyright：©2025 乐辰生物
"""
from PyQt5 import Qt
from AppContexts.Contexts import WebSocketContext
from AppInterfaces.ImplInterfaces import WebClientInterface, WebServerInterface
from AppInterfaces.AppTimeLoop import AppTimeLoop
from AppUtils.AppUtils import AppUtils
from AppCore.Requests import Request, Response
from AppCore.Levels import WebAPILevel
from AppCore.AppImpls.WebSocketImpl import WebSocketImpl
from AppSettings.Settings import (RECODE_FAILURE, RECODE_SUCCEED, SIGNAL_CONNECTION_TYPE, CODE_SUCCESS, CODE_FAILURE, CODE_WARNING)
DEFAULT_WEBSERVER_NAME          : str = "MicroscopeScanWebServer"
DEFAULT_WEBSERVER_SECURE_MODE   = Qt.QWebSocketServer.SslMode.NonSecureMode
SOCKET_SERVER_MAX_CONNECT_DELAY     : int = 2000
SOCKET_SERVER_PROCESS_EVENT_DELAY   : int = 500
class WebServerImpl(Qt.QObject, WebServerInterface):
    TransmitFrame: Qt.pyqtSignal = Qt.pyqtSignal(object)
    ReceivedFrame: Qt.pyqtSignal = Qt.pyqtSignal(object)

    @classmethod
    def instance(cls, context=None, parent: Qt.QObject = None) -> 'WebServerImpl':
        result: cls = cls.__new__(cls)
        result.__init__(context, parent)
        return result

    def __init__(self, context=None, parent: Qt.QObject = None):
        super(WebServerImpl, self).__init__(parent=parent)
        self.Parameter = context
        self.Initialization('WebSocketImpl', self, parent)

    def deleValue(self):
        super(WebServerImpl, self).deleValue()
        if self.hasManager:
            self.deleServerConnect(self.Manager)
        self.Close()
        self.Manager    = None
        self.Parameter  = None
        self.Handles    = []

    def deleProperty(self):
        super(WebServerImpl, self).deleProperty()
        self.deleHandles()

    def initConnect(self):
        super(WebServerImpl, self).initConnect()
        TYPE: Qt.Qt.ConnectionType = Qt.Qt.ConnectionType(Qt.Qt.AutoConnection | Qt.Qt.UniqueConnection)
        self.TransmitFrame.connect(slot=self.slot_SocketTransmitFrame, type=TYPE)

    def deleConnect(self):
        super(WebServerImpl, self).deleConnect()
        try:
            self.TransmitFrame.disconnect(self.slot_SocketTransmitFrame)
        except Exception as e:
            pass

    
    def Open(self, timeOut: int = 1000, **args) -> int:
        global SOCKET_SERVER_MAX_CONNECT_DELAY, SOCKET_SERVER_PROCESS_EVENT_DELAY
        waittimes: int = max(abs(timeOut), SOCKET_SERVER_MAX_CONNECT_DELAY)
        self.initContext()
        if not self.hasManager:
            self.initManager()
        if not self.hasManager:
            return RECODE_FAILURE
        if self.IsOpen:
            return RECODE_SUCCEED
        url: Qt.QUrl = Qt.QUrl(self.Parameter.API)
        print(url, url.port(), url.host())
        self.Parameter.IsOpen = self.Manager.listen(Qt.QHostAddress(url.host()), url.port(self.Parameter.Port))
        endtime: Qt.QDateTime = Qt.QDateTime.currentDateTime().addMSecs(waittimes)
        while True:
            if Qt.QDateTime.currentDateTime() > endtime or self.Parameter.IsOpen:
                break
            AppTimeLoop.processEvents(SOCKET_SERVER_PROCESS_EVENT_DELAY)
            self.Parameter.IsOpen = self.Manager.listen(Qt.QHostAddress(self.Parameter.Addr), url.port(self.Parameter.Port))

        return RECODE_SUCCEED if self.Parameter.IsOpen else RECODE_FAILURE

    
    def Close(self, timeOut: int = 1000, **args) -> int:
        global SOCKET_SERVER_MAX_CONNECT_DELAY, SOCKET_SERVER_PROCESS_EVENT_DELAY
        waittimes: int = max(abs(timeOut), SOCKET_MAX_CONNECT_DELAY)
        self.initContext()
        if not self.isValid:
            return RECODE_SUCCEED
        if not self.IsOpen:
            return RECODE_SUCCEED
        self.Manager.close()
        endtime: Qt.QDateTime = Qt.QDateTime.currentDateTime().addMSecs(waittimes)
        while True:
            self.Parameter.IsOpen = self.Manager.isListening()
            if Qt.QDateTime.currentDateTime() > endtime or not self.Parameter.IsOpen:
                break
            AppTimeLoop.processEvents(PROCESS_EVENT_DELAY)
            self.Manager.close()
        return RECODE_SUCCEED if self.Parameter.IsOpen else RECODE_FAILURE

    
    def initManager(self, **args):
        global DEFAULT_WEBSERVER_NAME, DEFAULT_WEBSERVER_SECURE_MODE
        self.initContext()
        if not self.hasParameter:
            self.Parameter = WebSocketContext()
        self.initHandles()
        if not self.hasManager:
            self.Manager = Qt.QWebSocketServer(DEFAULT_WEBSERVER_NAME, DEFAULT_WEBSERVER_SECURE_MODE)
            self.initServerConnect(self.Manager)

    
    def deleManager(self):
        self.Close()
        self.deleHandles()
        try:
            self.Manager.deleteLater()
            AppTimeLoop.processGlobalEvents(1000)
        except Exception as e:
            AppUtils.print_Exception(e)
        self.Manager = None

    def initServerConnect(self, socket: Qt.QWebSocketServer):
        if not isinstance(socket, Qt.QWebSocketServer):
            return
        TYPE: Qt.Qt.ConnectionType = Qt.Qt.ConnectionType(Qt.Qt.AutoConnection | Qt.Qt.UniqueConnection)
        socket.acceptError.connect(slot=self.slot_acceptError, type=TYPE)
        socket.serverError.connect(slot=self.slot_serverError, type=TYPE)
        socket.newConnection.connect(slot=self.slot_newConnection, type=TYPE)

    def deleServerConnect(self, socket: Qt.QWebSocketServer):
        if not isinstance(socket, Qt.QWebSocketServer):
            return
        socket.acceptError.disconnect()
        socket.serverError.disconnect()
        socket.newConnection.disconnect()

    def initSocketConnect(self, socket):
        from AppCore.AppImpls.WebSocketImpl import WebSocketImpl
        if not isinstance(socket, WebSocketImpl):
            return
        TYPE: Qt.Qt.ConnectionType = Qt.Qt.ConnectionType(Qt.Qt.AutoConnection | Qt.Qt.UniqueConnection)
        socket.ReceivedFrame        .connect(slot=self.slot_SocketReceivedFrame , type=TYPE)
        socket.ConnectedSignal      .connect(slot=self.slot_SocketConnected     , type=TYPE)
        socket.DisconnectedSignal   .connect(slot=self.slot_SocketDisconnected  , type=TYPE)

    def deleSocketConnect(self, socket):
        from AppCore.AppImpls.WebSocketImpl import WebSocketImpl
        if not isinstance(socket, WebSocketImpl):
            return
        try:
            socket.ReceivedFrame.disconnect()
            socket.ConnectedSignal.disconnect()
            socket.DisconnectedSignal.disconnect()
        except Exception as e:
            AppUtils.print_Exception(e)

    def initHandles(self):
        Locker: Qt.QWriteLocker = Qt.QWriteLocker(self.IOLocker)
        if not self.hasHandles:
            self.Handles = []

    def deleHandles(self):
        Locker: Qt.QWriteLocker = Qt.QWriteLocker(self.IOLocker)
        if not self.hasHandles:
            return
        while not self.isEmpty:
            value = self.Handles.pop(0)
            if value is not None:
                del value

    
    def initContext(self):
        if not self.hasParameter:
            from AppSettings.AppSetting import AppSetting, AppConfig
            self.Parameter = AppConfig.WebSocket.copy()
        if not self.hasParameter:
            self.Parameter = WebSocketContext()


    def slot_acceptError(self, socketError):
        server: Qt.QWebSocketServer = self.sender()
        if not isinstance(server, Qt.QWebSocketServer):
            return
        from AppLog.logHelper import logWEBSERVER
        logWEBSERVER << AppUtils.current_function_info( f"ADDR: {server.serverAddress().toString()} Port: {server.serverPort()} Error: {socketError}")

        pass

    def slot_serverError(self, closeCode):
        server: Qt.QWebSocketServer = self.sender()
        if not isinstance(server, Qt.QWebSocketServer):
            return
        from AppLog.logHelper import logWEBSERVER
        logWEBSERVER << AppUtils.current_function_info(f"ADDR: {server.serverAddress().toString()} Port: {server.serverPort()} closeCode: {closeCode}")
        pass

    def slot_newConnection(self):
        Server: Qt.QWebSocketServer = self.sender()
        if not isinstance(Server, Qt.QWebSocketServer):
            return
        if not self.hasParameter:
            self.initContext()

        socket: Qt.QWebSocket = Server.nextPendingConnection()
        if not isinstance(socket, Qt.QWebSocket):
            return
        from AppLog.logHelper import logWEBSERVER
        from AppCore.AppImpls.WebSocketImpl import WebSocketImpl
        try:
            info: str = AppUtils.current_function_info(
                f"Server: {Server.serverUrl()} ADDR: {socket.peerAddress().toString()} Port: {socket.peerPort()}")
            logWEBSERVER << info
            print(info, len(self.Handles))
            handler: WebSocketImpl = WebSocketImpl.instance(context=self.Parameter.copy(), socket=socket, parent=self)
            index: int = self.indexOf(handler)
            if index >= 0:
                return
            response: Response = Request.NoneWebAPI(handle=None, code=CODE_SUCCESS, message="连接成功")
            print(response.toJson())
            handler.TransmitFrame.emit(response.toJson())
            self.initSocketConnect(handler)
            Locker: Qt.QWriteLocker = Qt.QWriteLocker(self.IOLocker)
            self.Handles.append(handler)
        except Exception as e:
            AppUtils.print_Exception(e)
        pass

    def slot_SocketReceivedFrame(self, buffer):

        self.ReceivedFrame.emit(buffer)
        pass

    def slot_SocketConnected(self, request: Request):
        if not isinstance(request, Request):
            return
        index: int
        number: int = len(self.Handles)
        if isinstance(request.Handler, WebSocketImpl):
            index = self.indexOf(request.Handler)

        elif isinstance(request.Handler, Qt.QWebSocket):
            index = self.indexOf(request.Handler)
        else:
            index = number
        if index < 0:
            self.Handles.append(request.Handler)
        pass

    def slot_SocketDisconnected(self, request: Request):
        if not isinstance(request, Request):
            return
        index: int
        if isinstance(request.Handler, WebSocketImpl):
            index = self.indexOf(request.Handler)
        elif isinstance(request.Handler, Qt.QWebSocket):
            index = self.indexOf(request.Handler)
        else:
            index = -1
        if index >= 0:
            self.Handles.pop(index)
            if isinstance(request.Handler, WebSocketImpl):
                request.Handler.deleteLater()
                request.Handler = None
            elif isinstance(request.Handler, Qt.QWebSocket):
                request.Handler.deleteLater()
                request.Handler = None

    def slot_SocketTransmitFrame(self, buffer):
        self.TransmitString(buffer)
        pass

    def slot_WebServerTransmit(self, name: str, buffer):
        if name == self.__class__.__name__:
            self.TransmitString(buffer)
        pass

    def TransmitString(self, buffer, **args) -> int:
        if len(self.Handles) <= 0:
            return RECODE_SUCCEED
        socket: WebServerImpl
        for index, socket in enumerate(self.Handles):
            if socket is not None and socket.IsOpen:
                socket.TransmitFrame.emit(buffer)
        return RECODE_SUCCEED


    
    def TransmitBinary(self, buffer, **args) -> int:
        if len(self.Handles) <= 0:
            return RECODE_SUCCEED
        socket: WebServerImpl
        for index, socket in enumerate(self.Handles):
            if socket is not None:
                socket.TransmitFrame.emit(buffer)
        return RECODE_SUCCEED
