#if os(Windows)
import Foundation
import WinSDK

/// The Windows leg of ``SecretFile``: "owner only" expressed as an NTFS DACL
/// (docs/WINDOWS_PORT.md §4.3).
///
/// `chmod 0600` has no NTFS equivalent — `FileManager`'s `.posixPermissions` attribute is
/// accepted and ignored on Windows, so the POSIX hardening the credential call sites perform is a
/// silent no-op there. What replaces it: build a fresh ACL containing exactly one ACE (the calling
/// user, full control) and install it as a **protected** DACL, which both replaces whatever the
/// file inherited from its parent and stops future inheritance. That is the closest true analogue
/// of a 0600 file owned by the user — Administrators and SYSTEM can of course still take
/// ownership, exactly as root can on POSIX.
///
/// Directories additionally get `CONTAINER_INHERIT | OBJECT_INHERIT` on the ACE, so files created
/// inside a hardened directory start out hardened even if a writer forgets to call back here —
/// the moral equivalent of a 0700 dir.
///
/// Compiles and links on Windows 11 amd64 (2026-07-29). The DACL itself is not yet asserted by a
/// test — nothing in the Carbon suite reads back an ACL — so treat "owner only" here as reviewed
/// and building, not proven. A round-trip test belongs with the DPAPI `CredentialStore` (§4.2).
enum WindowsFilePermissions {
    struct Failure: Error, CustomStringConvertible {
        let api: String
        let code: DWORD
        var description: String { "\(api) failed (Win32 \(code))" }
    }

    // Spelled out rather than taken from WinSDK's imported macros: `DACL_SECURITY_INFORMATION`
    // and friends are `long` constants whose Swift import shape (Int32 vs UInt32, signed
    // `0x80000000`) varies with the SDK/toolchain pairing, and every one of them is a fixed
    // documented bit. `SECURITY_INFORMATION` itself is a `DWORD`.
    private static let daclSecurityInformation: DWORD = 0x0000_0004
    private static let protectedDaclSecurityInformation: DWORD = 0x8000_0000
    private static let genericAll: DWORD = 0x1000_0000
    private static let noInheritance: DWORD = 0x0000_0000
    /// `CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE` — children of a hardened dir inherit the ACE.
    private static let subContainersAndObjectsInherit: DWORD = 0x0000_0003

    /// Replace `path`'s DACL with a protected, single-ACE list granting the current user full
    /// control. Throws ``Failure`` with the Win32 error on any step.
    static func restrictToOwner(path: String, isDirectory: Bool) throws {
        try withCurrentUserSID { sid in
            var access = EXPLICIT_ACCESS_W()
            access.grfAccessPermissions = genericAll
            access.grfAccessMode = SET_ACCESS
            access.grfInheritance = isDirectory ? subContainersAndObjectsInherit : noInheritance
            access.Trustee.pMultipleTrustee = nil
            access.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE
            access.Trustee.TrusteeForm = TRUSTEE_IS_SID
            access.Trustee.TrusteeType = TRUSTEE_IS_USER
            // TRUSTEE_IS_SID smuggles a PSID through the LPWSTR field — the documented idiom.
            access.Trustee.ptstrName = sid.assumingMemoryBound(to: WCHAR.self)

            var acl: PACL?
            // Compared against the literal 0 rather than `ERROR_SUCCESS`: these two APIs return
            // `DWORD`, while the SDK's `ERROR_SUCCESS` is a signed `LONG` — Swift won't compare
            // the two, and a literal adapts to whichever width the import produced.
            let aclRC = SetEntriesInAclW(1, &access, nil, &acl)
            guard aclRC == 0, let acl else {
                throw Failure(api: "SetEntriesInAclW", code: aclRC)
            }
            defer { LocalFree(acl) }

            let rc = path.withCString(encodedAs: UTF16.self) { name in
                SetNamedSecurityInfoW(
                    UnsafeMutablePointer(mutating: name), SE_FILE_OBJECT,
                    daclSecurityInformation | protectedDaclSecurityInformation,
                    nil, nil, acl, nil)
            }
            guard rc == 0 else {
                throw Failure(api: "SetNamedSecurityInfoW", code: rc)
            }
        }
    }

    /// Run `body` with the calling process token's user SID. The SID points into a buffer that
    /// lives only for the call, so `body` must finish using it before returning — which is why
    /// the ACL is built and installed *inside* the closure rather than the SID being returned.
    private static func withCurrentUserSID(_ body: (PSID) throws -> Void) throws {
        var token: HANDLE?
        // `.boolValue` throughout: older toolchains import Win32 `BOOL` as `WindowsBool`, which
        // can't stand alone in a condition. See the `Bool.boolValue` shim in WindowsSupport.swift
        // for why that spelling works on toolchains that import it as plain `Bool` too.
        guard OpenProcessToken(GetCurrentProcess(), DWORD(TOKEN_QUERY), &token).boolValue,
            let token
        else {
            throw Failure(api: "OpenProcessToken", code: GetLastError())
        }
        defer { CloseHandle(token) }

        // Probe for the size first: TOKEN_USER is variable-length (it carries the SID inline).
        var size: DWORD = 0
        _ = GetTokenInformation(token, TokenUser, nil, 0, &size)
        guard size > 0 else {
            throw Failure(api: "GetTokenInformation(size)", code: GetLastError())
        }
        var buffer = [UInt8](repeating: 0, count: Int(size))
        // `withUnsafeMutableBytes` rethrows, so a failure inside propagates directly — and the ACL
        // work has to happen in here, because the SID points into this buffer.
        try buffer.withUnsafeMutableBytes { raw in
            guard let base = raw.baseAddress,
                GetTokenInformation(token, TokenUser, base, size, &size).boolValue
            else {
                throw Failure(api: "GetTokenInformation", code: GetLastError())
            }
            let user = base.assumingMemoryBound(to: TOKEN_USER.self).pointee
            guard let sid = user.User.Sid else {
                throw Failure(api: "GetTokenInformation(sid)", code: 0)
            }
            try body(sid)
        }
    }
}
#endif
