const {
    describe,
    test,
    expect,
} = require('@jest/globals')
const { WebDriver } = require('../common/web_driver')
const {
    inflate,
    deflate,
} = require('pako')
const fs = require('fs')
const path = require('node:path')
const root = require('./hotconi/proto/market.v2.trade')
// Static code + Reflection + .proto parser

const timeout = 9999999

async function sleep (ms) {
    return new Promise(resolve => setTimeout(resolve, ms))
}

describe('hotcoin站点测试', () => {

    let targetInfo = {
        'targetId': '',
        'type': '',
        'title': '',
        'url': '',
        'attached': true,
        'canAccessOpener': false,
        'browserContextId': '',
    }

    const driver = new WebDriver({
        // port: 23035,
    })

    const init = async () => {
        // await driver.setProxy('socks://localhost:8880')
        await driver.setProxy('http://172.16.1.132:3128')

        await driver.builder()

        let target = await driver.cdp.Target

        targetInfo = await target.getTargetInfo()

        console.info('info>>>>', targetInfo)

    }

    const baseUrl = 'https://www.hotcoin.com/'

    const prefix = 'hotcoin'

    let cookiesPath = path.join(__dirname, 'tmp', prefix + '_cookies')

    let storagePath = path.join(__dirname, 'tmp', prefix + '_storage')

    test('测试打开', async (done) => {

        await init()

        const page = driver.cdp.Page

        page.navigate({ url: baseUrl })

        done()

    }, timeout)

    const login = async (Storage, Runtime) => {
        let cookie = '', localStorage = ''
        if (fs.existsSync(cookiesPath)) {
            cookie = fs.readFileSync(cookiesPath, 'utf8')
        }
        // 借助localStorage中的jwt信息登录
        if (fs.existsSync(storagePath)) {

            localStorage = fs.readFileSync(storagePath, 'utf8')

        }

        if (cookie) {
            await Storage.setCookies(JSON.parse(cookie))
        }

        if (localStorage) {
            let storage = {}
            try {
                storage = JSON.parse(`${localStorage}`) ||{}
            } catch (e) {
                console.error(e)
            }

            // let script = `
            //     for (const k in storage) {
            //         localStorage.setItem(k,storage[k]);
            //     }
            // `

            // script=`
            //       localStorage.setItem('aaa','bbb')
            // `
            // await Runtime.evaluate({
            //     expression: `localStorage.setItem('aaa','>>>>>')`,
            //     // awaitPromise: true,
            // });
            for (const k in storage) {
                await Runtime.evaluate({
                    expression: `localStorage.setItem(\`${k}\`, \`${storage[k]}\`)`,
                    // awaitPromise: true,
                })
            }
        }
    }

    test('自动登录', async (done) => {
        await init()
        const {
            Storage,
            Page,
            Runtime,
        } = driver.cdp

        await Runtime.enable()

        try {
            Page.navigate({ url: baseUrl })

            await login(Storage, Runtime)

            let t = Date.now()

            let s = setInterval(async () => {

                let cookies = await Storage.getCookies()

                fs.writeFileSync(cookiesPath, JSON.stringify(cookies), 'utf8')

                let localStorage = await Runtime.evaluate({
                    expression: 'JSON.stringify(localStorage)',
                })

                fs.writeFileSync(storagePath, localStorage?.result?.value, 'utf8')

                if (Date.now() - t > 5 * 60 * 1000) {

                    clearInterval(s)
                }
            }, 1000)

        } catch (e) {
            console.error(e)
        }

        await sleep(timeout)
        done()
    }, timeout)

    test('监听wss', async (done) => {

        await init()

        const {
            Storage,
            Page,
            Network,
            Runtime,
        } = driver.cdp

        Network.enable()

        Page.navigate({ url: baseUrl })

        await login(Storage, Runtime)

        //这个网站连接了3个wss，不同的wss的数据结构不一样。
        // "wss://wsw.spentr.com/trade/multiple",
        //"wss://wcws.spentr.com/",
        const requestInfo = {}

        const decodeWsw = (data) => {

            let res = inflate(data/* , { to: 'string' } */)

            console.info('解压缩结果：', res)
            switch (res) {
                case 'pong':
                    return res

                default: {
                    let root = require('./hotconi/proto/market.v2.trade')

                    let response = root.market.v2.trade.Response.decode(res)

                    let object = response.toJSON()

                    console.info('=decodeWsw==>', object)
                }
            }

        }

        const decodeWsws = (data) => {

            let res = inflate(data/* , { to: 'string' } */)

            //字符串中有2个隐藏字符 DCC EM
            let regex = new RegExp('(\\n|' + String.fromCharCode(18) + '|' + String.fromCharCode(30)+ '|' + String.fromCharCode(31) + ')', 'g')

            let keys = inflate(data, { to: 'string' }).split(regex).filter(s => (s || '').includes('type.googleapis.com')).flatMap(s => (s || '').split('/'))
            // CommonPbMsg
            console.info('解压缩结果：', res)
            switch (res) {
                case 'pong':
                    return res

                default: {
                    let root = require('./hotconi/proto/' + (keys.join('.') || '').replaceAll('"', ''))

                    let response = root.type.googleapis.com[keys[1]].Response.decode(res)

                    let object = response.toJSON()

                    console.info('=decodeWsws==>', object)
                }
            }

        }

        // 一个二进制数据流还原
        // opcode number WebSocket message opcode.
        //     mask boolean WebSocket message mask.
        //     payloadData string WebSocket message payload data. If the opcode is 1, this is a text message and payloadData is a UTF-8 string.
        //     If the opcode isn't 1, then payloadData is a base64 encoded string representing binary data.
        const formatResponse = (params = {
            requestId: '',
            timestamp: '',
            response: {
                opcode: 1,
                mask: false,
                payloadData: '',
            },

        }) => {
            try {

                if (!params.response?.opcode) {
                    return params.response
                }

                if (params.response?.opcode === 1) {
                    return params.response.payloadData
                }

                const binaryData = Buffer.from(params.response.payloadData, 'base64')

                let res = {}
                if ((requestInfo[params.requestId].url || '').includes('wsw.spentr.com')) {
                    res = decodeWsw(binaryData)
                } else if ((requestInfo[params.requestId].url || '').includes('wcws.spentr.com')) {
                    res = decodeWsws(binaryData)
                }
                console.info('结果解析：', res)
            } catch (e) {
                console.error(e)
            }
        }

        Network.requestWillBeSent((params) => {
            console.log('Request Headers:', params.request.headers);
        });


        Network.webSocketCreated(params => {
            console.log('WebSocket created:', params.url)
            requestInfo[params.requestId] = {
                url: params.url,
            }
        })
        // 订阅 Network.webSocketFrameSent 和 Network.webSocketFrameReceived 事件,监听 WebSocket 帧的发送和接收:

        // 订阅 Network.webSocketClosed 事件,监听 WebSocket 连接的关闭:

        Network.webSocketClosed(params => {
            console.log('WebSocket closed:', params.closeCode, params.closeReason)
            // formatResponse(params)
        })

        // 订阅Network.webSocketWillSendHandshakeRequest事件,拦截WebSocket连接的握手请求:

        Network.webSocketWillSendHandshakeRequest(params => {
            console.log('WebSocket handshake request:', params.request)
            // formatResponse(params)
        })

        // 订阅Network.webSocketHandshakeResponseReceived事件,拦截WebSocket连接的握手响应:

        Network.webSocketHandshakeResponseReceived(params => {
            console.log('WebSocket handshake response:', params.response)
            let data = formatResponse(params)
            console.info('webSocketHandshakeResponseReceived解析结果:', data)
        })

        // 订阅Network.webSocketFrameSent和Network.webSocketFrameReceived事件,拦截WebSocket数据帧的发送和接收:

        Network.webSocketFrameSent(params => {
            console.log('WebSocket frame sent:', params.response)
            // formatResponse(params)
        })

        Network.webSocketFrameReceived(params => {
            // console.log('WebSocket frame received:', params.response)
            console.info('webSocketFrameReceived 回复', params.response)
            let data = formatResponse(params)
            console.info('webSocketFrameReceived解析结果:', data)
        })
        Network.webSocketFrameError(params => {
            console.log('WebSocket frame error:', params.response)
            // let data = formatResponse(params)
            // console.info('webSocketFrameError解析结果:', data)
        })
        await sleep(timeout)
        done()
    }, timeout)

    test('拆包', done => {
        let str = `0{"sid":"b6535f35-3047-4f12-9cd3-c526b39cd019","upgrades":["websocket"],"pingInterval":30000,"pingTimeout":60000}`

        while (/^\d/.test(str)) {
            str = str.substring(1)
        }
        try {
            JSON.parse(str)
        } catch (e) {
            console.error(e)
        }
        console.info(str)
        done()
    })
})
