import { sendNoticeWs, type ParsedNoticeWsMessage } from '@/lib/notices/wsNotice'

type PendingEntry = {
    resolve: (msg: ParsedNoticeWsMessage) => void
    reject: (err: Error) => void
    timer: number | ReturnType<typeof setTimeout>
}

const pending = new Map<string, PendingEntry>()

let rpcSeq = 0

function nextRequestId(): string {
    rpcSeq += 1
    return `nr_${rpcSeq}_${Date.now()}`
}

export function settleNoticeWsRpc(msg: ParsedNoticeWsMessage): boolean {
    const requestId =
        typeof msg.requestId === 'string' ? String(msg.requestId).trim() : ''
    if (!requestId) return false
    const entry = pending.get(requestId)
    if (!entry) return false
    window.clearTimeout(entry.timer)
    pending.delete(requestId)
    if (msg.type === 'error') {
        entry.reject(new Error(String(msg.message || msg.error || 'Request failed')))
        return true
    }
    entry.resolve(msg)
    return true
}

export function rejectAllNoticeWsRpc(reason = 'WebSocket closed') {
    for (const [id, entry] of pending) {
        window.clearTimeout(entry.timer)
        entry.reject(new Error(reason))
        pending.delete(id)
    }
}

export function noticeWsRequest(
    ws: WebSocket,
    type: string,
    payload: Record<string, unknown> = {},
    timeoutMs = 12_000
): Promise<ParsedNoticeWsMessage> {
    if (ws.readyState !== WebSocket.OPEN) {
        return Promise.reject(new Error('WebSocket not connected'))
    }
    const requestId = nextRequestId()
    return new Promise((resolve, reject) => {
        const timer = window.setTimeout(() => {
            pending.delete(requestId)
            reject(new Error('Request timeout'))
        }, timeoutMs)
        pending.set(requestId, { resolve, reject, timer })
        sendNoticeWs(ws, { type, requestId, ...payload })
    })
}
