// 假设 PlatformSettings 是一个全局对象，这里简单模拟
const PlatformSettings = {
    ServiceAddress: 'localhost:8080',
    Timeout: 5000,
    Encoding: 'utf-8'
};

// 假设 PlatformLogger 是一个全局对象，这里简单模拟
const PlatformLogger = {
    SystemErrorInfo: (message: string, error: Error) => {
        console.error(`${message} ${error.message}`);
    }
};

class SocketTran {
    private static readonly _transDataLen = 1024;
    private _mySocket: WebSocket | null = null;
    private readonly _serviceAddress = PlatformSettings.ServiceAddress;
    private readonly _timeout = PlatformSettings.Timeout;

    private constructor() {}

    static GetInstance(): SocketTran {
        return new SocketTran();
    }

    private async Connect(timeout = 0): Promise<boolean> {
        try {
            const [address, portStr] = PlatformSettings.ServiceAddress.split(':');
            const portArray = portStr.split(',');
            const port = parseInt(portArray[Math.floor(Math.random() * portArray.length)], 10);
            const url = `ws://${address}:${port}`;

            return new Promise<boolean>((resolve, reject) => {
                const socket = new WebSocket(url);
                this._mySocket = socket;

                const timeoutId = setTimeout(() => {
                    socket.close();
                    reject(new Error('Connection timed out'));
                }, timeout <= 0 ? this._timeout : timeout);

                socket.onopen = () => {
                    clearTimeout(timeoutId);
                    resolve(true);
                };

                socket.onerror = (error) => {
                    clearTimeout(timeoutId);
                    PlatformLogger.SystemErrorInfo('Socket连接失败！', error as Error);
                    resolve(false);
                };
            });
        } catch (e) {
            PlatformLogger.SystemErrorInfo('Socket连接失败！', e as Error);
            return false;
        }
    }

    async Send(msgData: Uint8Array, timeout = 0): Promise<Uint8Array> {
        for (let i = 0; i < 3; i++) {
            if (await this.Connect(timeout)) {
                break;
            }
            await new Promise(resolve => setTimeout(resolve, 100));
        }

        return this.MsgSend(msgData);
    }

    private async MsgSend(integrateData: Uint8Array): Promise<Uint8Array> {
        if (!this._mySocket) {
            throw new Error('Socket is not connected');
        }

        try {
            let index = 0;
            let lastCnt = integrateData.length;

            // 循环发送数据
            while (lastCnt > 0) {
                let tmpData: Uint8Array;
                if (lastCnt > SocketTran._transDataLen) {
                    tmpData = new Uint8Array(SocketTran._transDataLen);
                    tmpData.set(integrateData.subarray(index, index + SocketTran._transDataLen));
                    this._mySocket.send(tmpData);
                    index += SocketTran._transDataLen;
                    lastCnt -= SocketTran._transDataLen;
                } else {
                    tmpData = new Uint8Array(lastCnt);
                    tmpData.set(integrateData.subarray(index, index + lastCnt));
                    this._mySocket.send(tmpData);
                    lastCnt = 0;
                }
            }

            // 接收头部8位数据长度
            const headByte = await this.receiveBytes(8);
            const header = new TextDecoder(PlatformSettings.Encoding).decode(headByte);
            const getDataLength = parseInt(header, 10);

            // 接收数据包
            const memoryStream = new Uint8Array(getDataLength + 8);
            memoryStream.set(headByte, 0);
            let receivedLength = 0;

            while (receivedLength < getDataLength) {
                const receiveBuffer = await this.receiveBytes(Math.min(getDataLength - receivedLength, SocketTran._transDataLen));
                memoryStream.set(receiveBuffer, 8 + receivedLength);
                receivedLength += receiveBuffer.length;
            }

            this._mySocket.close();
            return memoryStream;
        } catch (ex) {
            if (this._mySocket) {
                this._mySocket.close();
            }
            PlatformLogger.SystemErrorInfo('Socket通讯失败！错误原因：', ex as Error);
            throw ex;
        }
    }

    private receiveBytes(length: number): Promise<Uint8Array> {
        if (!this._mySocket) {
            throw new Error('Socket is not connected');
        }

        return new Promise<Uint8Array>((resolve, reject) => {
            const buffer = new Uint8Array(length);
            let receivedLength = 0;

            const onMessage = (event: MessageEvent) => {
                const data = new Uint8Array(event.data);
                const remainingLength = length - receivedLength;
                const copyLength = Math.min(remainingLength, data.length);
                buffer.set(data.subarray(0, copyLength), receivedLength);
                receivedLength += copyLength;

                if (receivedLength === length) {
                    this._mySocket?.removeEventListener('message', onMessage);
                    resolve(buffer);
                }
            };

            const onError = (error: Event) => {
                this._mySocket?.removeEventListener('message', onMessage);
                this._mySocket?.removeEventListener('error', onError);
                reject(error);
            };

            this._mySocket.addEventListener('message', onMessage);
            this._mySocket.addEventListener('error', onError);
        });
    }
}

export default SocketTran;