import Foundation

enum DockerExec {
    static func run(
        composeFile: String, service: String,
        command: [String],
        timeout: TimeInterval = 60,
    ) throws {
        let process = Process()
        process.executableURL = URL(fileURLWithPath: "/usr/bin/env")
        process.arguments = [
            "docker", "compose", "-f", composeFile,
            "exec", "-T", "-u", "git", service,
        ] + command

        let stderrPipe = Pipe()
        process.standardError = stderrPipe
        process.standardOutput = FileHandle.nullDevice

        let didExit = DispatchSemaphore(value: 0)
        process.terminationHandler = { _ in didExit.signal() }

        try process.run()

        // Enforce a timeout so a hung `docker compose exec` (a known Docker-on-macOS flake)
        // fails fast and can be retried, instead of blocking the whole seed indefinitely.
        if didExit.wait(timeout: .now() + timeout) == .timedOut {
            process.terminate()
            _ = didExit.wait(timeout: .now() + 5)
            throw SeedError.dockerExecTimedOut(
                command: command.joined(separator: " "),
                seconds: timeout,
            )
        }

        if process.terminationStatus != 0 {
            let stderrData = stderrPipe.fileHandleForReading.readDataToEndOfFile()
            let stderr = String(data: stderrData, encoding: .utf8) ?? ""
            throw SeedError.dockerExecFailed(
                command: command.joined(separator: " "),
                exitCode: process.terminationStatus,
                stderr: stderr,
            )
        }
    }
}
