import Foundation
import os

private let readinessLog = Logger(subsystem: "com.nucleic", category: "macvm.readiness")

// MARK: - The base readiness gate
//
// Provisioning's recurring failure mode has not been any single bug — it's been *stamping success on
// unverified state*. Three separate times a base was published as "provisioned, recipe N" while
// clones of it were unusable: an agent-less base (clones pinned at "Booting…"), a base whose
// network-volume consent was never answered (clones hung on their first repo touch), and a base
// whose consent probe checked an easier path than production uses (so it passed vacuously).
//
// The structural fix is this gate: before a base is ever stamped, run the ACTUAL production path
// against it and refuse the base if any leg fails. Every check here mirrors exactly what a session
// clone does on its first turn — same mount shape, same exec surface, same shell — so "the gate
// passed" and "a session works" cannot diverge. A base that fails is left unstamped and detectably
// stale, so the next launch retries rather than shipping a broken guest.
extension MacVMEngine {
    /// What the gate checked, for the log and for an actionable failure message.
    struct BaseReadinessReport: Sendable {
        /// The workspace share was mounted at its original absolute host path and is readable —
        /// the `mount_virtiofs` + read that every session boot performs (and that an un-granted
        /// network-volume consent silently blocks).
        var workspaceMounted = false
        /// nash is installed where the exec surface requires it (docs/NASH.md §7.5 — the guest
        /// refuses to run commands under anything else, so a nash-less base has a dead exec surface).
        var nashInstalled = false
        /// A plain command completed over the exec channel — the surface `mac_vm_exec` rides.
        var execWorks = false
        /// Round-trip seconds for the whole probe. A base that only *eventually* answers is a base
        /// whose first real command will look like a hang, so this is reported even on success.
        var roundTripSeconds: Double = 0
        var failures: [String] = []

        var isReady: Bool { failures.isEmpty }
        var summary: String {
            "workspace=\(workspaceMounted) nash=\(nashInstalled) exec=\(execWorks) "
                + String(format: "rtt=%.1fs", roundTripSeconds)
        }
    }

    /// Markers the probe script echoes. Parsed rather than inferred from the exit code so a partial
    /// failure names the leg that broke instead of collapsing to "exit 1".
    enum ReadinessMarker {
        static let mounted = "NUCLEIC_READY_WORKSPACE"
        static let nash = "NUCLEIC_READY_NASH"
        static let exec = "NUCLEIC_READY_EXEC"
    }

    /// Build the probe script: mount the workspace exactly as a session does, read it, confirm nash,
    /// and prove the exec surface round-trips. `mountPoint` is where the share lands *in the guest*
    /// (``macOSMountPoint(_:)``) — the path the read must target, since reading anything easier is
    /// what let a broken base pass. Pure, so the contract is unit-testable without a VM.
    static func baseReadinessScript(mountPoint: String, mountScript: String) -> String {
        let quoted = shQuote(mountPoint)
        return """
        \(mountScript)
        /bin/ls \(quoted) >/dev/null 2>&1 && echo \(ReadinessMarker.mounted)
        [ -x \(shQuote(guestNashPath)) ] && echo \(ReadinessMarker.nash)
        echo \(ReadinessMarker.exec)
        """
    }

    /// Where the guest agent requires nash to live (mirrors `VMAgentCore.ExecSession.defaultNashPath`;
    /// the guest package isn't linkable from the host, so the constant is duplicated deliberately).
    static let guestNashPath = "/usr/local/bin/nash"
}

#if arch(arm64)
extension MacVMEngine {
    /// Run the production path against a booted base and report what worked. Bounded, so a base that
    /// hangs (the classic un-granted-consent symptom) fails the gate instead of hanging the caller.
    func verifyBaseReadiness(
        instance: MacVMInstance, hostPath: String
    ) async throws -> BaseReadinessReport {
        var report = BaseReadinessReport()
        let mount = Self.consentProbeMount(hostDirectory: hostPath)
        let mountPoint = Self.macOSMountPoint(mount)
        let script = Self.baseReadinessScript(
            mountPoint: mountPoint,
            mountScript: Self.hostPathRecreationScript(os: .macOS, mounts: [mount]) ?? "")

        let started = Date()
        let channel = try await openExecChannel(
            instance: instance, label: Self.baseConsentSurfaceName, workdir: nil, env: [:],
            remoteBody: script)
        async let outText = Self.drainLines(channel.stdoutLines)
        async let errText = Self.drainLines(channel.stderrLines)
        let outcome = await Self.awaitExit(channel, timeoutNanos: 60 * 1_000_000_000)
        let stdout = await outText
        let stderr = await errText
        report.roundTripSeconds = Date().timeIntervalSince(started)

        guard case .exited = outcome else {
            report.failures.append(
                "the base never answered a command within 60s — the classic symptom of an unanswered "
                    + "network-volume consent prompt blocking the first share access")
            return report
        }
        report.workspaceMounted = stdout.contains(ReadinessMarker.mounted)
        report.nashInstalled = stdout.contains(ReadinessMarker.nash)
        report.execWorks = stdout.contains(ReadinessMarker.exec)

        if !report.execWorks {
            let detail = stderr.trimmingCharacters(in: .whitespacesAndNewlines)
            report.failures.append(
                "the exec surface produced no output"
                    + (detail.isEmpty ? "" : " (stderr: \(detail.suffix(300)))"))
        }
        if !report.nashInstalled {
            report.failures.append(
                "nash is missing at \(Self.guestNashPath) — the guest exec surface is nash-only "
                    + "(docs/NASH.md §7.5), so every command in a clone would be refused")
        }
        if !report.workspaceMounted {
            report.failures.append(
                "the workspace share could not be mounted/read at \(mountPoint) — clones would fail "
                    + "or hang on their first repo access")
        }
        readinessLog.error("base readiness: \(report.summary, privacy: .public)")
        return report
    }
}
#endif
