import { isNodeLike } from './runtime'

type RuntimeClipboardNavigator = {
  clipboard?: Pick<Clipboard, 'writeText'>
}

type RuntimeDocument = Document & {
  execCommand?: (commandId: string) => boolean
}

type RuntimeGlobals = typeof globalThis & {
  navigator?: RuntimeClipboardNavigator
  process?: Pick<NodeJS.Process, 'platform' | 'stdout'>
  document?: RuntimeDocument
}

function runtimeGlobals(): RuntimeGlobals {
  return globalThis as RuntimeGlobals
}

/**
 * Best-effort text copy for both browser and terminal environments.
 *
 * Order:
 * 1) Browser `navigator.clipboard`
 * 2) Node platform clipboard utilities (pbcopy / clip / wl-copy / xclip / xsel)
 * 3) OSC 52 (terminal clipboard escape sequence)
 * 4) `document.execCommand('copy')` fallback
 */
export async function copyTextToClipboard(text: string): Promise<boolean> {
  const value = String(text ?? '')
  if (!value) return false

  const nav = runtimeGlobals().navigator
  if (nav?.clipboard?.writeText) {
    try {
      await nav.clipboard.writeText(value)
      return true
    } catch {
      // Fallback below.
    }
  }

  if (isNodeLike()) {
    try {
      const proc = runtimeGlobals().process
      const platform = String(proc?.platform || '')
      const { spawn } = await import('node:child_process')
      const run = (cmd: string, args: string[]): Promise<boolean> =>
        new Promise((resolve) => {
          try {
            const child = spawn(cmd, args, {
              stdio: ['pipe', 'ignore', 'ignore'],
              windowsHide: true,
            })
            child.on('error', () => resolve(false))
            child.on('close', (code) => resolve(code === 0))
            child.stdin?.write(value, 'utf8')
            child.stdin?.end()
          } catch {
            resolve(false)
          }
        })
      if (platform === 'darwin') {
        if (await run('pbcopy', [])) return true
      } else if (platform === 'win32') {
        if (await run('cmd', ['/c', 'clip'])) return true
      } else {
        if (await run('wl-copy', [])) return true
        if (await run('xclip', ['-selection', 'clipboard'])) return true
        if (await run('xsel', ['--clipboard', '--input'])) return true
      }
    } catch {
      // Fallback below.
    }
  }

  const proc = runtimeGlobals().process
  if (proc?.stdout?.write && proc?.stdout?.isTTY) {
    try {
      const base64 = isNodeLike()
        ? (await import('node:buffer')).Buffer.from(value, 'utf8').toString(
            'base64',
          )
        : btoa(unescape(encodeURIComponent(value)))
      proc.stdout.write(`\u001B]52;c;${base64}\u0007`)
      return true
    } catch {
      // Fallback below.
    }
  }

  const doc = runtimeGlobals().document
  if (
    !doc?.createElement ||
    !doc?.body?.appendChild ||
    typeof doc.execCommand !== 'function'
  )
    return false

  try {
    const prevActive = doc.activeElement as HTMLElement | null
    const ta = doc.createElement('textarea') as HTMLTextAreaElement
    ta.value = value
    ta.setAttribute('readonly', 'true')
    ta.setAttribute('aria-hidden', 'true')
    ta.style.position = 'fixed'
    ta.style.left = '-9999px'
    ta.style.top = '-9999px'
    ta.style.opacity = '0'
    doc.body.appendChild(ta)
    ta.focus()
    ta.select()
    ta.setSelectionRange(0, ta.value.length)
    const ok = Boolean(doc.execCommand('copy'))
    ta.remove()
    try {
      prevActive?.focus?.({ preventScroll: true })
    } catch {
      prevActive?.focus?.()
    }
    return ok
  } catch {
    return false
  }
}

/**
 * Clear the clipboard by writing an empty string.
 */
export async function clearClipboard(): Promise<boolean> {
  return copyTextToClipboard('')
}
