import { spawn, type ChildProcess } from 'node:child_process'
import { existsSync, readdirSync } from 'node:fs'
import { join } from 'node:path'
import { getPipeBundleDir } from './pipe-path'
import { PIPE_PATH } from './client'

/** 本进程拉起的 pipe 服务端子进程（若由外部已启动同名管道，不会记录在此） */
let spawnedPipeServer: ChildProcess | null = null

function getPipeServerExecutablePath(): string {
  const dir = getPipeBundleDir()
  if (process.platform === 'win32') {
    return join(dir, 'pipe.exe')
  }
  return join(dir, 'pipe')
}

function getPipeName(pipePath: string): string {
  return pipePath.replace(/^\\\\\.\\pipe\\/, '')
}

function hasNamedPipe(pipePath: string): boolean {
  try {
    return readdirSync('\\\\.\\pipe\\').includes(getPipeName(pipePath))
  } catch {
    return false
  }
}

async function waitUntilPipeAppears(totalMs: number, intervalMs: number): Promise<void> {
  const deadline = Date.now() + totalMs
  while (Date.now() < deadline) {
    if (hasNamedPipe(PIPE_PATH)) {
      return
    }
    await new Promise((r) => setTimeout(r, intervalMs))
  }
  throw new Error(`Pipe server not ready after ${totalMs}ms`)
}

/**
 * Windows：若命名管道尚不可用，则从 `resources/pipe` 启动 `pipe.exe`，阻塞直到可连。
 * 若管道已存在（用户已手动启动服务端），则直接返回。
 * 若未找到打包的 `pipe.exe`，仅打日志，不抛错（仍可连接外部服务端）。
 */
export async function ensurePipeServerRunning(): Promise<void> {
  console.log('[pipe] ensurePipeServerRunning', process.platform)
  if (process.platform !== 'win32') {
    console.warn('[pipe] only supported on Windows')
    return
  }

  if (hasNamedPipe(PIPE_PATH)) {
    console.log('[pipe] pipe server already running')
    return
  }

  const exe = getPipeServerExecutablePath()
  if (!existsSync(exe)) {
    console.warn('[pipe] bundled pipe server not found, skip auto-start')
    return
  }

  const child = spawn(exe, [], {
    cwd: getPipeBundleDir(),
    detached: false,
    stdio: 'ignore'
    // 是否隐藏窗口
    // windowsHide: true
  })
  spawnedPipeServer = child

  child.on('error', (err) => {
    console.error('[pipe] 启动 pipe 服务端失败:', err.message)
  })

  child.once('exit', (code, signal) => {
    if (spawnedPipeServer === child) {
      spawnedPipeServer = null
    }
    if (code !== 0 && code !== null) {
      console.warn('[pipe] 服务端进程退出:', { code, signal })
    }
  })

  await waitUntilPipeAppears(25_000, 200)
}

export function stopSpawnedPipeServer(): void {
  const child = spawnedPipeServer
  if (!child || child.killed) {
    spawnedPipeServer = null
    return
  }
  try {
    child.kill()
  } catch {
    // ignore
  }
  spawnedPipeServer = null
}
