import { markRaw } from 'vue'
import type { FitAddon } from '@xterm/addon-fit'
import type { Terminal } from '@xterm/xterm'
import type { TermSessionNative } from './types'

const nativeMap = new Map<string, TermSessionNative>()

function emptyNative(): TermSessionNative {
  return {
    ws: null,
    term: null,
    fitAddon: null,
    resizeObserver: null,
    reconnectTimer: null,
    pingTimer: null,
    uptimeTimer: null,
  }
}

export function createNative(sessionId: string): TermSessionNative {
  const native = emptyNative()
  nativeMap.set(sessionId, native)
  return native
}

export function getNative(sessionId: string): TermSessionNative | undefined {
  return nativeMap.get(sessionId)
}

export function deleteNative(sessionId: string): void {
  nativeMap.delete(sessionId)
}

export function setNativeTerm(sessionId: string, term: Terminal): void {
  const n = getNative(sessionId)
  if (n) n.term = markRaw(term)
}

export function setNativeFitAddon(sessionId: string, fitAddon: FitAddon): void {
  const n = getNative(sessionId)
  if (n) n.fitAddon = markRaw(fitAddon)
}

export function setNativeResizeObserver(sessionId: string, ro: ResizeObserver): void {
  const n = getNative(sessionId)
  if (n) n.resizeObserver = markRaw(ro)
}

export function isSessionWsOpen(sessionId: string): boolean {
  const ws = getNative(sessionId)?.ws
  return ws?.readyState === WebSocket.OPEN
}

export function forEachNative(
  fn: (sessionId: string, native: TermSessionNative) => void,
): void {
  nativeMap.forEach((native, sessionId) => fn(sessionId, native))
}

export function clearAllNatives(): void {
  nativeMap.clear()
}
