//comment this line and last to dev
export function wmillTsDev(port: number) { return `
let reqs: Record<string, any> = {}
let ws: WebSocket | null = null
let wsReady: Promise<void>
let wsReadyResolve: () => void

function initWebSocket() {
    wsReady = new Promise((resolve) => {
        wsReadyResolve = resolve
    })

    ws = new WebSocket('ws://localhost:${port}')

    ws.onopen = () => {
        console.log('[wmill] WebSocket connected')
        wsReadyResolve()
    }

    ws.onmessage = (event) => {
        const data = JSON.parse(event.data)
        if (data.type === 'streamJobUpdate') {
            // Handle streaming update
            const job = reqs[data.reqId]
            if (job && job.onUpdate) {
                job.onUpdate({
                    new_result_stream: data.new_result_stream,
                    stream_offset: data.stream_offset
                })
            }
        } else if (data.type === 'streamJobRes') {
            // Handle stream completion
            const job = reqs[data.reqId]
            if (job) {
                if (data.error) {
                    job.reject(new Error(data.result?.stack ?? data.result?.message ?? 'Stream error'))
                } else {
                    job.resolve(data.result)
                }
                delete reqs[data.reqId]
            }
        } else if (data.type === 'backendRes' || data.type === 'backendAsyncRes') {
            console.log('Message from WebSocket backend', data)
            const job = reqs[data.reqId]
            if (job) {
                const result = data.result
                if (data.error) {
                    job.reject(new Error(result.stack ?? result.message))
                } else {
                    job.resolve(result)
                }
                delete reqs[data.reqId]
            } else {
                console.error('No job found for', data.reqId)
            }
        }
    }

    ws.onerror = (error) => {
        console.error('[wmill] WebSocket error:', error)
    }

    ws.onclose = () => {
        console.log('[wmill] WebSocket closed, reconnecting...')
        setTimeout(initWebSocket, 1000)
    }
}

initWebSocket()

async function doRequest(type: string, o: object) {
    await wsReady
    return new Promise((resolve, reject) => {
        const reqId = Math.random().toString(36)
        reqs[reqId] = { resolve, reject }
        ws?.send(JSON.stringify({ ...o, type, reqId }))
    })
}

export const backend = new Proxy(
    {},
    {
        get(_, runnable_id: string) {
            return (v: any) => {
                return doRequest('backend', { runnable_id, v })
            }
        }
    })

export const backendAsync = new Proxy(
    {},
    {
        get(_, runnable_id: string) {
            return (v: any) => {
                return doRequest('backendAsync', { runnable_id, v })
            }
        }
    })

export function waitJob(jobId: string) {
    return doRequest('waitJob', { jobId })
}

export function getJob(jobId: string) {
    return doRequest('getJob', { jobId })
}

/**
 * Stream job results using SSE. Calls onUpdate for each stream update,
 * and resolves with the final result when the job completes.
 * @param jobId - The job ID to stream
 * @param onUpdate - Callback for stream updates with new_result_stream data
 * @returns Promise that resolves with the final job result
 */
export function streamJob(
    jobId: string,
    onUpdate?: (data: { new_result_stream?: string; stream_offset?: number }) => void
): Promise<any> {
    return new Promise(async (resolve, reject) => {
        await wsReady
        const reqId = Math.random().toString(36)
        reqs[reqId] = { resolve, reject, onUpdate }
        ws?.send(JSON.stringify({ jobId, type: 'streamJob', reqId }))
    })
}
`}