//===----------------------------------------------------------------------===//
// Copyright © 2025-2026 Apple Inc. and the Containerization project authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//===----------------------------------------------------------------------===//

/// NOTE: This is not a complete recreation of the runtime spec. Other platforms outside of Linux
/// have been left off, and some APIs for Linux aren't present. This was manually ported starting
/// at the v1.2.0 release.

public struct Spec: Codable, Sendable {
    public var version: String
    public var hooks: Hooks?
    public var process: Process?
    public var hostname, domainname: String
    public var mounts: [Mount]
    public var annotations: [String: String]?
    public var root: Root?
    public var linux: Linux?

    public init(
        version: String = "",
        hooks: Hooks? = nil,
        process: Process? = nil,
        hostname: String = "",
        domainname: String = "",
        mounts: [Mount] = [],
        annotations: [String: String]? = nil,
        root: Root? = nil,
        linux: Linux? = nil
    ) {
        self.version = version
        self.hooks = hooks
        self.process = process
        self.hostname = hostname
        self.domainname = domainname
        self.mounts = mounts
        self.annotations = annotations
        self.root = root
        self.linux = linux
    }

    public enum CodingKeys: String, CodingKey {
        case version = "ociVersion"
        case hooks
        case process
        case hostname
        case domainname
        case mounts
        case annotations
        case root
        case linux
    }

    public init(from decoder: Decoder) throws {
        self.init()

        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.version = try container.decode(String.self, forKey: .version)
        self.hooks = try container.decodeIfPresent(Hooks.self, forKey: .hooks)
        self.process = try container.decodeIfPresent(Process.self, forKey: .process)
        if let hostname = try container.decodeIfPresent(String.self, forKey: .hostname) {
            self.hostname = hostname
        }
        if let domainname = try container.decodeIfPresent(String.self, forKey: .domainname) {
            self.domainname = domainname
        }
        if let mounts = try container.decodeIfPresent([Mount].self, forKey: .mounts) {
            self.mounts = mounts
        }
        self.annotations = try container.decodeIfPresent([String: String].self, forKey: .annotations)
        self.root = try container.decodeIfPresent(Root.self, forKey: .root)
        self.linux = try container.decodeIfPresent(Linux.self, forKey: .linux)
    }
}

public struct Process: Codable, Sendable {
    public var cwd: String
    public var env: [String]
    public var consoleSize: Box?
    public var selinuxLabel: String
    public var noNewPrivileges: Bool
    public var commandLine: String
    public var oomScoreAdj: Int?
    public var capabilities: LinuxCapabilities?
    public var apparmorProfile: String
    public var user: User
    public var rlimits: [POSIXRlimit]
    public var args: [String]
    public var terminal: Bool

    public enum CodingKeys: String, CodingKey {
        case cwd
        case env
        case consoleSize
        case selinuxLabel
        case noNewPrivileges
        case commandLine
        case oomScoreAdj
        case capabilities
        case apparmorProfile
        case user
        case rlimits
        case args
        case terminal
    }

    public init(
        args: [String] = [],
        cwd: String = "/",
        env: [String] = [],
        consoleSize: Box? = nil,
        selinuxLabel: String = "",
        noNewPrivileges: Bool = false,
        commandLine: String = "",
        oomScoreAdj: Int? = nil,
        capabilities: LinuxCapabilities? = nil,
        apparmorProfile: String = "",
        user: User = .init(),
        rlimits: [POSIXRlimit] = [],
        terminal: Bool = false
    ) {
        self.cwd = cwd
        self.env = env
        self.consoleSize = consoleSize
        self.selinuxLabel = selinuxLabel
        self.noNewPrivileges = noNewPrivileges
        self.commandLine = commandLine
        self.oomScoreAdj = oomScoreAdj
        self.capabilities = capabilities
        self.apparmorProfile = apparmorProfile
        self.user = user
        self.rlimits = rlimits
        self.args = args
        self.terminal = terminal
    }

    public init(from config: ImageConfig) {
        let cwd = config.workingDir ?? "/"
        let env = config.env ?? []
        let args = (config.entrypoint ?? []) + (config.cmd ?? [])
        let user: User = {
            if let rawString = config.user {
                return User(username: rawString)
            }
            return User()
        }()
        self.init(args: args, cwd: cwd, env: env, user: user)
    }

    public init(from decoder: Decoder) throws {
        self.init()

        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.cwd = try container.decode(String.self, forKey: .cwd)
        if let env = try container.decodeIfPresent([String].self, forKey: .env) {
            self.env = env
        }
        self.consoleSize = try container.decodeIfPresent(Box.self, forKey: .consoleSize)
        if let selinuxLabel = try container.decodeIfPresent(String.self, forKey: .selinuxLabel) {
            self.selinuxLabel = selinuxLabel
        }
        if let noNewPrivileges = try container.decodeIfPresent(Bool.self, forKey: .noNewPrivileges) {
            self.noNewPrivileges = noNewPrivileges
        }
        if let commandLine = try container.decodeIfPresent(String.self, forKey: .commandLine) {
            self.commandLine = commandLine
        }
        self.oomScoreAdj = try container.decodeIfPresent(Int.self, forKey: .oomScoreAdj)
        self.capabilities = try container.decodeIfPresent(LinuxCapabilities.self, forKey: .capabilities)
        if let apparmorProfile = try container.decodeIfPresent(String.self, forKey: .apparmorProfile) {
            self.apparmorProfile = apparmorProfile
        }
        self.user = try container.decode(User.self, forKey: .user)
        if let rlimits = try container.decodeIfPresent([POSIXRlimit].self, forKey: .rlimits) {
            self.rlimits = rlimits
        }
        if let args = try container.decodeIfPresent([String].self, forKey: .args) {
            self.args = args
        }
        if let terminal = try container.decodeIfPresent(Bool.self, forKey: .terminal) {
            self.terminal = terminal
        }
    }
}

public struct LinuxCapabilities: Codable, Sendable {
    public var bounding: [String]?
    public var effective: [String]?
    public var inheritable: [String]?
    public var permitted: [String]?
    public var ambient: [String]?

    enum CodingKeys: String, CodingKey {
        case bounding
        case effective
        case inheritable
        case permitted
        case ambient
    }

    public init(
        bounding: [String]? = nil,
        effective: [String]? = nil,
        inheritable: [String]? = nil,
        permitted: [String]? = nil,
        ambient: [String]? = nil
    ) {
        self.bounding = bounding
        self.effective = effective
        self.inheritable = inheritable
        self.permitted = permitted
        self.ambient = ambient
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.bounding = try container.decodeIfPresent([String].self, forKey: .bounding)
        self.effective = try container.decodeIfPresent([String].self, forKey: .effective)
        self.inheritable = try container.decodeIfPresent([String].self, forKey: .inheritable)
        self.permitted = try container.decodeIfPresent([String].self, forKey: .permitted)
        self.ambient = try container.decodeIfPresent([String].self, forKey: .ambient)
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encodeIfPresent(bounding, forKey: .bounding)
        try container.encodeIfPresent(effective, forKey: .effective)
        try container.encodeIfPresent(inheritable, forKey: .inheritable)
        try container.encodeIfPresent(permitted, forKey: .permitted)
        try container.encodeIfPresent(ambient, forKey: .ambient)
    }
}

public struct Box: Codable, Sendable {
    var height, width: UInt

    public init(height: UInt, width: UInt) {
        self.height = height
        self.width = width
    }
}

public struct User: Codable, Sendable {
    public var uid: UInt32
    public var gid: UInt32
    public var umask: UInt32?
    public var additionalGids: [UInt32]
    public var username: String

    public enum CodingKeys: String, CodingKey {
        case uid
        case gid
        case umask
        case additionalGids
        case username
    }

    public init(
        uid: UInt32 = 0,
        gid: UInt32 = 0,
        umask: UInt32? = nil,
        additionalGids: [UInt32] = [],
        username: String = ""
    ) {
        self.uid = uid
        self.gid = gid
        self.umask = umask
        self.additionalGids = additionalGids
        self.username = username
    }

    public init(from decoder: Decoder) throws {
        self.init()

        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.uid = try container.decode(UInt32.self, forKey: .uid)
        self.gid = try container.decode(UInt32.self, forKey: .gid)
        self.umask = try container.decodeIfPresent(UInt32.self, forKey: .umask)
        if let additionalGids = try container.decodeIfPresent([UInt32].self, forKey: .additionalGids) {
            self.additionalGids = additionalGids
        }
        if let username = try container.decodeIfPresent(String.self, forKey: .username) {
            self.username = username
        }
    }
}

public struct Root: Codable, Sendable {
    public var path: String
    public var readonly: Bool

    public enum CodingKeys: String, CodingKey {
        case path
        case readonly
    }

    public init(path: String, readonly: Bool) {
        self.path = path
        self.readonly = readonly
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.path = try container.decode(String.self, forKey: .path)
        self.readonly = try container.decodeIfPresent(Bool.self, forKey: .readonly) ?? false
    }
}

public struct Mount: Codable, Sendable {
    public var type: String
    public var source: String
    public var destination: String
    public var options: [String]

    public var uidMappings: [LinuxIDMapping]?
    public var gidMappings: [LinuxIDMapping]?

    public enum CodingKeys: String, CodingKey {
        case type
        case source
        case destination
        case options
        case uidMappings
        case gidMappings
    }

    public init(
        type: String = "",
        source: String = "",
        destination: String,
        options: [String] = [],
        uidMappings: [LinuxIDMapping]? = nil,
        gidMappings: [LinuxIDMapping]? = nil
    ) {
        self.destination = destination
        self.type = type
        self.source = source
        self.options = options
        self.uidMappings = uidMappings
        self.gidMappings = gidMappings
    }

    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.type = try container.decodeIfPresent(String.self, forKey: .type) ?? ""
        self.source = try container.decodeIfPresent(String.self, forKey: .source) ?? ""
        self.destination = try container.decode(String.self, forKey: .destination)
        self.options = try container.decodeIfPresent([String].self, forKey: .options) ?? []
        self.uidMappings = try container.decodeIfPresent([LinuxIDMapping].self, forKey: .uidMappings)
        self.gidMappings = try container.decodeIfPresent([LinuxIDMapping].self, forKey: .gidMappings)
    }

    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(type, forKey: .type)
        try container.encode(source, forKey: .source)
        try container.encode(destination, forKey: .destination)
        try container.encode(options, forKey: .options)
        try container.encodeIfPresent(uidMappings, forKey: .uidMappings)
        try container.encodeIfPresent(gidMappings, forKey: .gidMappings)
    }
}

public struct Hook: Codable, Sendable {
    public var path: String
    public var args: [String]
    public var env: [String]
    public var timeout: Int?

    public init(path: String, args: [String], env: [String], timeout: Int?) {
        self.path = path
        self.args = args
        self.env = env
        self.timeout = timeout
    }
}

public struct Hooks: Codable, Sendable {
    public var prestart: [Hook]
    public var createRuntime: [Hook]
    public var createContainer: [Hook]
    public var startContainer: [Hook]
    public var poststart: [Hook]
    public var poststop: [Hook]

    public init(
        prestart: [Hook],
        createRuntime: [Hook],
        createContainer: [Hook],
        startContainer: [Hook],
        poststart: [Hook],
        poststop: [Hook]
    ) {
        self.prestart = prestart
        self.createRuntime = createRuntime
        self.createContainer = createContainer
        self.startContainer = startContainer
        self.poststart = poststart
        self.poststop = poststop
    }
}

public struct Linux: Codable, Sendable {
    public var uidMappings: [LinuxIDMapping]
    public var gidMappings: [LinuxIDMapping]
    public var sysctl: [String: String]?
    public var resources: LinuxResources?
    public var cgroupsPath: String
    public var namespaces: [LinuxNamespace]
    public var devices: [LinuxDevice]
    public var seccomp: LinuxSeccomp?
    public var rootfsPropagation: String
    public var maskedPaths: [String]
    public var readonlyPaths: [String]
    public var mountLabel: String
    public var personality: LinuxPersonality?

    public enum CodingKeys: String, CodingKey {
        case uidMappings
        case gidMappings
        case sysctl
        case resources
        case cgroupsPath
        case namespaces
        case devices
        case seccomp
        case rootfsPropagation
        case maskedPaths
        case readonlyPaths
        case mountLabel
        case personality
    }

    public init(
        uidMappings: [LinuxIDMapping] = [],
        gidMappings: [LinuxIDMapping] = [],
        sysctl: [String: String]? = nil,
        resources: LinuxResources? = nil,
        cgroupsPath: String = "",
        namespaces: [LinuxNamespace] = [],
        devices: [LinuxDevice] = [],
        seccomp: LinuxSeccomp? = nil,
        rootfsPropagation: String = "",
        maskedPaths: [String] = [],
        readonlyPaths: [String] = [],
        mountLabel: String = "",
        personality: LinuxPersonality? = nil
    ) {
        self.uidMappings = uidMappings
        self.gidMappings = gidMappings
        self.sysctl = sysctl
        self.resources = resources
        self.cgroupsPath = cgroupsPath
        self.namespaces = namespaces
        self.devices = devices
        self.seccomp = seccomp
        self.rootfsPropagation = rootfsPropagation
        self.maskedPaths = maskedPaths
        self.readonlyPaths = readonlyPaths
        self.mountLabel = mountLabel
        self.personality = personality
    }

    public init(from decoder: Decoder) throws {
        self.init()

        let container = try decoder.container(keyedBy: CodingKeys.self)
        if let uidMappings = try container.decodeIfPresent([LinuxIDMapping].self, forKey: .uidMappings) {
            self.uidMappings = uidMappings
        }
        if let gidMappings = try container.decodeIfPresent([LinuxIDMapping].self, forKey: .gidMappings) {
            self.gidMappings = gidMappings
        }
        self.sysctl = try container.decodeIfPresent([String: String].self, forKey: .sysctl)
        self.resources = try container.decodeIfPresent(LinuxResources.self, forKey: .resources)
        if let cgroupsPath = try container.decodeIfPresent(String.self, forKey: .cgroupsPath) {
            self.cgroupsPath = cgroupsPath
        }
        if let namespaces = try container.decodeIfPresent([LinuxNamespace].self, forKey: .namespaces) {
            self.namespaces = namespaces
        }
        if let devices = try container.decodeIfPresent([LinuxDevice].self, forKey: .devices) {
            self.devices = devices
        }
        self.seccomp = try container.decodeIfPresent(LinuxSeccomp.self, forKey: .seccomp)
        if let rootfsPropagation = try container.decodeIfPresent(String.self, forKey: .rootfsPropagation) {
            self.rootfsPropagation = rootfsPropagation
        }
        if let maskedPaths = try container.decodeIfPresent([String].self, forKey: .maskedPaths) {
            self.maskedPaths = maskedPaths
        }
        if let readonlyPaths = try container.decodeIfPresent([String].self, forKey: .readonlyPaths) {
            self.readonlyPaths = readonlyPaths
        }
        if let mountLabel = try container.decodeIfPresent(String.self, forKey: .mountLabel) {
            self.mountLabel = mountLabel
        }
        self.personality = try container.decodeIfPresent(LinuxPersonality.self, forKey: .personality)
    }
}

public struct LinuxNamespace: Codable, Sendable {
    public var type: LinuxNamespaceType
    public var path: String

    public init(type: LinuxNamespaceType, path: String = "") {
        self.type = type
        self.path = path
    }
}

public enum LinuxNamespaceType: String, Codable, Sendable {
    case pid
    case network
    case uts
    case mount
    case ipc
    case user
    case cgroup
}

public struct LinuxIDMapping: Codable, Sendable {
    public var containerID: UInt32
    public var hostID: UInt32
    public var size: UInt32

    public init(containerID: UInt32, hostID: UInt32, size: UInt32) {
        self.containerID = containerID
        self.hostID = hostID
        self.size = size
    }
}

public struct POSIXRlimit: Codable, Sendable {
    public var type: String
    public var hard: UInt64
    public var soft: UInt64

    public init(type: String, hard: UInt64, soft: UInt64) {
        self.type = type
        self.hard = hard
        self.soft = soft
    }
}

public struct LinuxHugepageLimit: Codable, Sendable {
    public var pagesize: String
    public var limit: UInt64

    public init(pagesize: String, limit: UInt64) {
        self.pagesize = pagesize
        self.limit = limit
    }
}

public struct LinuxInterfacePriority: Codable, Sendable {
    public var name: String
    public var priority: UInt32

    public init(name: String, priority: UInt32) {
        self.name = name
        self.priority = priority
    }
}

public struct LinuxBlockIODevice: Codable, Sendable {
    public var major: Int64
    public var minor: Int64

    public init(major: Int64, minor: Int64) {
        self.major = major
        self.minor = minor
    }
}

public struct LinuxWeightDevice: Codable, Sendable {
    public var major: Int64
    public var minor: Int64
    public var weight: UInt16?
    public var leafWeight: UInt16?

    public init(major: Int64, minor: Int64, weight: UInt16?, leafWeight: UInt16?) {
        self.major = major
        self.minor = minor
        self.weight = weight
        self.leafWeight = leafWeight
    }
}

public struct LinuxThrottleDevice: Codable, Sendable {
    public var major: Int64
    public var minor: Int64
    public var rate: UInt64

    public init(major: Int64, minor: Int64, rate: UInt64) {
        self.major = major
        self.minor = minor
        self.rate = rate
    }
}

public struct LinuxBlockIO: Codable, Sendable {
    public var weight: UInt16?
    public var leafWeight: UInt16?
    public var weightDevice: [LinuxWeightDevice]
    public var throttleReadBpsDevice: [LinuxThrottleDevice]
    public var throttleWriteBpsDevice: [LinuxThrottleDevice]
    public var throttleReadIOPSDevice: [LinuxThrottleDevice]
    public var throttleWriteIOPSDevice: [LinuxThrottleDevice]

    public init(
        weight: UInt16?,
        leafWeight: UInt16?,
        weightDevice: [LinuxWeightDevice],
        throttleReadBpsDevice: [LinuxThrottleDevice],
        throttleWriteBpsDevice: [LinuxThrottleDevice],
        throttleReadIOPSDevice: [LinuxThrottleDevice],
        throttleWriteIOPSDevice: [LinuxThrottleDevice]
    ) {
        self.weight = weight
        self.leafWeight = leafWeight
        self.weightDevice = weightDevice
        self.throttleReadBpsDevice = throttleReadBpsDevice
        self.throttleWriteBpsDevice = throttleWriteBpsDevice
        self.throttleReadIOPSDevice = throttleReadIOPSDevice
        self.throttleWriteIOPSDevice = throttleWriteIOPSDevice
    }
}

public struct LinuxMemory: Codable, Sendable {
    public var limit: Int64?
    public var reservation: Int64?
    public var swap: Int64?
    public var kernel: Int64?
    public var kernelTCP: Int64?
    public var swappiness: UInt64?
    public var disableOOMKiller: Bool?
    public var useHierarchy: Bool?
    public var checkBeforeUpdate: Bool?

    public init(
        limit: Int64? = nil,
        reservation: Int64? = nil,
        swap: Int64? = nil,
        kernel: Int64? = nil,
        kernelTCP: Int64? = nil,
        swappiness: UInt64? = nil,
        disableOOMKiller: Bool? = nil,
        useHierarchy: Bool? = nil,
        checkBeforeUpdate: Bool? = nil
    ) {
        self.limit = limit
        self.reservation = reservation
        self.swap = swap
        self.kernel = kernel
        self.kernelTCP = kernelTCP
        self.swappiness = swappiness
        self.disableOOMKiller = disableOOMKiller
        self.useHierarchy = useHierarchy
        self.checkBeforeUpdate = checkBeforeUpdate
    }
}

public struct LinuxCPU: Codable, Sendable {
    public var shares: UInt64?
    public var quota: Int64?
    public var burst: UInt64?
    public var period: UInt64?
    public var realtimeRuntime: Int64?
    public var realtimePeriod: Int64?
    public var cpus: String
    public var mems: String
    public var idle: Int64?

    public init(
        shares: UInt64? = nil,
        quota: Int64? = nil,
        burst: UInt64? = nil,
        period: UInt64? = nil,
        realtimeRuntime: Int64? = nil,
        realtimePeriod: Int64? = nil,
        cpus: String = "",
        mems: String = "",
        idle: Int64? = nil
    ) {
        self.shares = shares
        self.quota = quota
        self.burst = burst
        self.period = period
        self.realtimeRuntime = realtimeRuntime
        self.realtimePeriod = realtimePeriod
        self.cpus = cpus
        self.mems = mems
        self.idle = idle
    }
}

public struct LinuxPids: Codable, Sendable {
    public var limit: Int64

    public init(limit: Int64) {
        self.limit = limit
    }
}

public struct LinuxNetwork: Codable, Sendable {
    public var classID: UInt32?
    public var priorities: [LinuxInterfacePriority]

    public init(classID: UInt32?, priorities: [LinuxInterfacePriority]) {
        self.classID = classID
        self.priorities = priorities
    }
}

public struct LinuxRdma: Codable, Sendable {
    public var hcsHandles: UInt32?
    public var hcaObjects: UInt32?

    public init(hcsHandles: UInt32?, hcaObjects: UInt32?) {
        self.hcsHandles = hcsHandles
        self.hcaObjects = hcaObjects
    }
}

public struct LinuxResources: Codable, Sendable {
    public var devices: [LinuxDeviceCgroup]
    public var memory: LinuxMemory?
    public var cpu: LinuxCPU?
    public var pids: LinuxPids?
    public var blockIO: LinuxBlockIO?
    public var hugepageLimits: [LinuxHugepageLimit]
    public var network: LinuxNetwork?
    public var rdma: [String: LinuxRdma]?
    public var unified: [String: String]?

    public init(
        devices: [LinuxDeviceCgroup] = [],
        memory: LinuxMemory? = nil,
        cpu: LinuxCPU? = nil,
        pids: LinuxPids? = nil,
        blockIO: LinuxBlockIO? = nil,
        hugepageLimits: [LinuxHugepageLimit] = [],
        network: LinuxNetwork? = nil,
        rdma: [String: LinuxRdma]? = nil,
        unified: [String: String] = [:]
    ) {
        self.devices = devices
        self.memory = memory
        self.cpu = cpu
        self.pids = pids
        self.blockIO = blockIO
        self.hugepageLimits = hugepageLimits
        self.network = network
        self.rdma = rdma
        self.unified = unified
    }
}

public struct LinuxDevice: Codable, Sendable {
    public var path: String
    public var type: String
    public var major: Int64
    public var minor: Int64
    public var fileMode: UInt32?
    public var uid: UInt32?
    public var gid: UInt32?

    public init(
        path: String,
        type: String,
        major: Int64,
        minor: Int64,
        fileMode: UInt32?,
        uid: UInt32?,
        gid: UInt32?
    ) {
        self.path = path
        self.type = type
        self.major = major
        self.minor = minor
        self.fileMode = fileMode
        self.uid = uid
        self.gid = gid
    }
}

public struct LinuxDeviceCgroup: Codable, Sendable {
    public var allow: Bool
    public var type: String
    public var major: Int64?
    public var minor: Int64?
    public var access: String?

    public init(allow: Bool, type: String, major: Int64?, minor: Int64?, access: String?) {
        self.allow = allow
        self.type = type
        self.major = major
        self.minor = minor
        self.access = access
    }
}

public enum LinuxPersonalityDomain: String, Codable, Sendable {
    case perLinux = "LINUX"
    case perLinux32 = "LINUX32"
}

public struct LinuxPersonality: Codable, Sendable {
    public var domain: LinuxPersonalityDomain
    public var flags: [String]

    public init(domain: LinuxPersonalityDomain, flags: [String]) {
        self.domain = domain
        self.flags = flags
    }
}

public struct LinuxSeccomp: Codable, Sendable {
    public var defaultAction: LinuxSeccompAction
    public var defaultErrnoRet: UInt?
    public var architectures: [Arch]
    public var flags: [LinuxSeccompFlag]
    public var listenerPath: String
    public var listenerMetadata: String
    public var syscalls: [LinuxSyscall]

    public init(
        defaultAction: LinuxSeccompAction,
        defaultErrnoRet: UInt?,
        architectures: [Arch],
        flags: [LinuxSeccompFlag],
        listenerPath: String,
        listenerMetadata: String,
        syscalls: [LinuxSyscall]
    ) {
        self.defaultAction = defaultAction
        self.defaultErrnoRet = defaultErrnoRet
        self.architectures = architectures
        self.flags = flags
        self.listenerPath = listenerPath
        self.listenerMetadata = listenerMetadata
        self.syscalls = syscalls
    }
}

public enum LinuxSeccompFlag: String, Codable, Sendable {
    case flagLog = "SECCOMP_FILTER_FLAG_LOG"
    case flagSpecAllow = "SECCOMP_FILTER_FLAG_SPEC_ALLOW"
    case flagWaitKillableRecv = "SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV"
}

public enum Arch: String, Codable, Sendable {
    case archX86 = "SCMP_ARCH_X86"
    case archX86_64 = "SCMP_ARCH_X86_64"
    case archX32 = "SCMP_ARCH_X32"
    case archARM = "SCMP_ARCH_ARM"
    case archAARCH64 = "SCMP_ARCH_AARCH64"
    case archMIPS = "SCMP_ARCH_MIPS"
    case archMIPS64 = "SCMP_ARCH_MIPS64"
    case archMIPS64N32 = "SCMP_ARCH_MIPS64N32"
    case archMIPSEL = "SCMP_ARCH_MIPSEL"
    case archMIPSEL64 = "SCMP_ARCH_MIPSEL64"
    case archMIPSEL64N32 = "SCMP_ARCH_MIPSEL64N32"
    case archPPC = "SCMP_ARCH_PPC"
    case archPPC64 = "SCMP_ARCH_PPC64"
    case archPPC64LE = "SCMP_ARCH_PPC64LE"
    case archS390 = "SCMP_ARCH_S390"
    case archS390X = "SCMP_ARCH_S390X"
    case archPARISC = "SCMP_ARCH_PARISC"
    case archPARISC64 = "SCMP_ARCH_PARISC64"
    case archRISCV64 = "SCMP_ARCH_RISCV64"
}

public enum LinuxSeccompAction: String, Codable, Sendable {
    case actKill = "SCMP_ACT_KILL"
    case actKillProcess = "SCMP_ACT_KILL_PROCESS"
    case actKillThread = "SCMP_ACT_KILL_THREAD"
    case actTrap = "SCMP_ACT_TRAP"
    case actErrno = "SCMP_ACT_ERRNO"
    case actTrace = "SCMP_ACT_TRACE"
    case actAllow = "SCMP_ACT_ALLOW"
    case actLog = "SCMP_ACT_LOG"
    case actNotify = "SCMP_ACT_NOTIFY"
}

public enum LinuxSeccompOperator: String, Codable, Sendable {
    case opNotEqual = "SCMP_CMP_NE"
    case opLessThan = "SCMP_CMP_LT"
    case opLessEqual = "SCMP_CMP_LE"
    case opEqualTo = "SCMP_CMP_EQ"
    case opGreaterEqual = "SCMP_CMP_GE"
    case opGreaterThan = "SCMP_CMP_GT"
    case opMaskedEqual = "SCMP_CMP_MASKED_EQ"
}

public struct LinuxSeccompArg: Codable, Sendable {
    public var index: UInt
    public var value: UInt64
    public var valueTwo: UInt64
    public var op: LinuxSeccompOperator

    public init(index: UInt, value: UInt64, valueTwo: UInt64, op: LinuxSeccompOperator) {
        self.index = index
        self.value = value
        self.valueTwo = valueTwo
        self.op = op
    }
}

public struct LinuxSyscall: Codable, Sendable {
    public var names: [String]
    public var action: LinuxSeccompAction
    public var errnoRet: UInt?
    public var args: [LinuxSeccompArg]

    public init(
        names: [String],
        action: LinuxSeccompAction,
        errnoRet: UInt?,
        args: [LinuxSeccompArg]
    ) {
        self.names = names
        self.action = action
        self.errnoRet = errnoRet
        self.args = args
    }
}
