/**
 * Service install dispatcher — PLAN_RELAY_AGENT T17. Detects the platform, writes the unit, and
 * loads it. REFUSES to install as root (EXPLORE §4d least privilege). All IO is injected so the
 * logic is unit-testable without touching the real system.
 */
import type { AgentConfig } from '../config/agentConfig.js'
import {
  buildLaunchdPlist,
  launchdLoadCommand,
  launchdPlistPath,
  launchdUnloadCommand,
} from './launchd.js'
import {
  buildSystemdUnit,
  systemdDisableCommand,
  systemdEnableCommand,
  systemdUnitPath,
} from './systemd.js'

export type ServicePlatform = 'launchd' | 'systemd'

export class RootRefusedError extends Error {
  constructor() {
    super('refusing to install the agent service as root — run as the logged-in user (least privilege)')
    this.name = 'RootRefusedError'
  }
}

export interface InstallDeps {
  writeFile(path: string, content: string): void
  runCommand(cmd: string, args: readonly string[]): Promise<void>
  getuid(): number
  homedir(): string
  username(): string
  binPath(): string
}

/** Map a Node platform to its service manager, or null if unsupported. */
export function detectPlatform(os: NodeJS.Platform): ServicePlatform | null {
  if (os === 'darwin') return 'launchd'
  if (os === 'linux') return 'systemd'
  return null
}

/** Write + load the service unit for `platform`. Throws RootRefusedError if running as root. */
export async function installService(
  _cfg: AgentConfig,
  platform: ServicePlatform,
  deps: InstallDeps,
): Promise<void> {
  if (deps.getuid() === 0) throw new RootRefusedError()
  const bin = deps.binPath()
  if (platform === 'launchd') {
    const path = launchdPlistPath(deps.homedir())
    deps.writeFile(path, buildLaunchdPlist(bin))
    const { cmd, args } = launchdLoadCommand(path)
    await deps.runCommand(cmd, args)
    return
  }
  const path = systemdUnitPath(deps.homedir())
  deps.writeFile(path, buildSystemdUnit(bin, deps.username()))
  const { cmd, args } = systemdEnableCommand()
  await deps.runCommand(cmd, args)
}

/** Unload the service unit for `platform`. */
export async function uninstallService(
  platform: ServicePlatform,
  deps: Pick<InstallDeps, 'runCommand' | 'homedir'>,
): Promise<void> {
  if (platform === 'launchd') {
    const { cmd, args } = launchdUnloadCommand(launchdPlistPath(deps.homedir()))
    await deps.runCommand(cmd, args)
    return
  }
  const { cmd, args } = systemdDisableCommand()
  await deps.runCommand(cmd, args)
}
