import Foundation

// Windows substitutes for the Apple-only surface NucleicCore leans on (docs/WINDOWS_PORT.md
// §4.3). This directory is compiled ONLY on Windows (excluded in Package.swift elsewhere).
//
// Most of the non-Darwin stand-ins already live in shared files behind `#if !canImport(...)`
// guards and compile here unchanged:
//   • the `os.Logger` shim — PortableLogging.swift
//   • `LinuxSecretStore` (interim, until the DPAPI `CredentialStore` of §4.2 lands),
//     the `MacVMManager` stub (the VM service is likewise absent on Windows), and the
//     `ContainerResourceSample`/`ContainerKillDiagnosis`/`ContainerEngine.ControlPlaneProbe`
//     value mirrors — LinuxSupport.swift
//
// Unlike Linux, Windows compiles the REAL `Container/ContainerManager.swift` against the
// `SandboxEngine` protocol (docs/WINDOWS_PORT.md §3.1); the wslc engine that satisfies it
// lands in `Container/Windows/` (work item 6).
//
// The §4.3 platform shims that have landed (work item 9):
//   • WindowsSignals.swift  — `pid_t` / `SIGKILL` / `SIGTERM` / `SIGINT` vocabulary
//   • ProcessTree.swift     — `kill()`, Job Objects, process table + CPU/IO sampling
//   • FilePermissions.swift — owner-only DACLs behind the shared `SecretFile`
//   • WindowsEnvironment.swift — registry `Path`, behind `LoginShellPATH`
//   • PowerBlocker.swift    — `SetThreadExecutionState` while sessions are active
//   • this file             — host executable resolution (below)
// Still outstanding: `WindowsDNSSD` (item 13) and the NIO LAN transports (item 8's tail).
// `FileWatcher` proved unnecessary — the `DispatchSource` uses §4.3 attributed to file watching
// are socket accept sources in `MCPApprovalServer` / `ClaudeTokenProxy`, and both already sit
// behind platform legs (NIO on Windows / Darwin-only respectively).

#if os(Windows)
/// Win32 `BOOL` is imported as Swift's own `Bool` by current toolchains, but as the `WindowsBool`
/// struct by older ones — and `WindowsBool` can't stand alone in a condition, so every Win32 call
/// site here spells the test `.boolValue`. Giving `Bool` the same member keeps those call sites
/// compiling under either importer instead of splitting them behind a toolchain check.
extension Bool {
    @inline(__always) var boolValue: Bool { self }
}

/// Resolve a bare executable name against `path` the way `CreateProcess` would if it did the
/// searching — every `PATH` directory crossed with every `PATHEXT` extension, plus the name as
/// given (so an explicit `git.exe` still resolves).
///
/// Needed because the POSIX spawn path leans on `/usr/bin/env` to do this, and Windows has no
/// equivalent: `Foundation.Process` resolves `executableURL` against the current directory, so a
/// bare `git` would spawn `<cwd>\git` and fail. Returns nil when nothing matches, which the caller
/// reports as a spawn failure — the same outcome as `env`'s exit 127.
func windowsResolveExecutable(_ name: String, path: String?) -> String? {
    let fm = FileManager.default
    let extensions = ((ProcessInfo.processInfo.environment["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD")
        .split(separator: ";", omittingEmptySubsequences: true).map(String.init))
    // An explicit extension is honored as-is before any PATHEXT expansion.
    let hasExtension = extensions.contains {
        name.lowercased().hasSuffix($0.lowercased())
    }
    // PATHEXT candidates FIRST, the bare name last. `CreateProcess` can only launch a real binary,
    // and cmd resolves a bare `git` by trying the PATHEXT extensions — so preferring the
    // extension-less name would pick a same-named script or data file that can't be launched.
    let candidates = hasExtension ? [name] : extensions.map { name + $0 } + [name]

    for directory in (path ?? "").split(separator: ";", omittingEmptySubsequences: true) {
        let base = String(directory)
        for candidate in candidates {
            let full = (base as NSString).appendingPathComponent(candidate)
            // `fileExists`, NOT `isExecutableFile`: corelibs-foundation's Windows
            // `isExecutableFile(atPath:)` answers from the PATHEXT-style extension rather than the
            // file, returning true for paths that do not exist. That resolved `git` to a
            // `git.COM` in whatever directory happens to be first on PATH — `Process.run()` then
            // failed with "The file doesn't exist", naming a file nothing had ever created.
            // A directory is excluded too: `<dir>\git\` must not shadow `<dir>\git.exe`.
            var isDirectory: ObjCBool = false
            if fm.fileExists(atPath: full, isDirectory: &isDirectory), !isDirectory.boolValue {
                return full
            }
        }
    }
    return nil
}
#endif
