#if os(Windows)
import Foundation
import WinSDK

/// The registry half of the Windows environment (docs/WINDOWS_PORT.md §4.3).
///
/// `LoginShellPATH` exists because a macOS GUI app inherits launchd's minimal `PATH`. Windows has
/// no such hole — Explorer hands a process the fully merged machine + user environment — but it
/// has a smaller one: `Path` is *stored* in the registry, and a process only ever sees the copy it
/// was born with. Install Git (or `gh`, or a Node toolchain) while `nucleic-hostd` is running and
/// its own `PATH` never learns about it, so every host spawn keeps reporting "not found" until the
/// host is restarted. Reading the two authoritative keys closes that gap without a shell probe.
///
/// Compiles and links on Windows 11 amd64 (2026-07-29); the registry read is not separately
/// asserted, but a wrong `Path` would surface immediately as a `git` that cannot be found.
enum WindowsEnvironment {
    /// The persisted `Path`, machine entries first then user entries — the same order Windows
    /// itself composes them in when it builds a new process's environment. `nil` if neither key
    /// could be read, which sends `LoginShellPATH` to its inherited-PATH fallback.
    static func registryPATH() -> String? {
        let machine = registryValue(
            root: HKEY_LOCAL_MACHINE,
            subkey: #"SYSTEM\CurrentControlSet\Control\Session Manager\Environment"#,
            name: "Path")
        let user = registryValue(root: HKEY_CURRENT_USER, subkey: "Environment", name: "Path")
        let parts = [machine, user].compactMap { $0 }.filter { !$0.isEmpty }
        return parts.isEmpty ? nil : parts.joined(separator: ";")
    }

    /// One string value, with `REG_EXPAND_SZ` references (`%SystemRoot%`, `%USERPROFILE%`)
    /// expanded — `RegGetValueW` does that by default, and an unexpanded `Path` entry would be a
    /// directory that exists nowhere.
    private static func registryValue(root: HKEY?, subkey: String, name: String) -> String? {
        var size: DWORD = 0
        let flags = DWORD(RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ)
        // Two-call idiom: probe for the byte length, then fetch.
        let probe = subkey.withCString(encodedAs: UTF16.self) { subkeyW in
            name.withCString(encodedAs: UTF16.self) { nameW in
                RegGetValueW(root, subkeyW, nameW, flags, nil, nil, &size)
            }
        }
        // Literal 0, not `ERROR_SUCCESS` — see the note in FilePermissions.swift.
        guard probe == 0, size > 0 else { return nil }

        // `size` is in bytes; the value is UTF-16 and includes its NUL terminator.
        var buffer = [UInt16](repeating: 0, count: Int(size) / MemoryLayout<UInt16>.size + 1)
        let read = subkey.withCString(encodedAs: UTF16.self) { subkeyW in
            name.withCString(encodedAs: UTF16.self) { nameW in
                buffer.withUnsafeMutableBytes { raw in
                    RegGetValueW(root, subkeyW, nameW, flags, nil, raw.baseAddress, &size)
                }
            }
        }
        guard read == 0 else { return nil }
        return String(decoding: buffer.prefix { $0 != 0 }, as: UTF16.self)
    }
}

// MARK: - POSIX environment mutation

// `setenv`/`unsetenv` used to live here. They moved to
// `Sources/NucleicProtocol/WindowsEnvironment.swift` — `NucleicProtocolTests` calls them, and that
// suite builds under `NUCLEIC_WINDOWS_PROTOCOL_ONLY=1`, where NucleicCore isn't in the manifest at
// all. NucleicCore re-exports NucleicProtocol, so call sites here are unaffected as long as the
// file importing them can see that module.
#endif
