import Foundation

/// Boundary validation, same rules as the server (frozen contract, plan §3.1).
/// Sources: src/protocol.ts:22-23 (SESSION_ID_RE), :113-115 (dimensions),
/// :142-149 (cwd). Pure functions, never throw.
public enum Validation {
    /// Byte-identical port of the server's SESSION_ID_RE
    /// (`/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i`):
    /// UUID v4 — 8-4-4-4-12 hex groups, version nibble '4', variant nibble
    /// 8/9/a/b, case-insensitive (M7). Vectors in ServerVectorTests pin the
    /// equivalence against a test-side mirror of the server regex.
    public static func isValidSessionId(_ candidate: String) -> Bool {
        let sessionIdRegex =
            /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/
            .ignoresCase()
        return candidate.wholeMatch(of: sessionIdRegex) != nil
    }

    /// Mirrors the server's `isValidDimension` range check for `resize`
    /// (integers in `WireConstants.resizeRange`). Frames outside this range
    /// are silently discarded by the server — validate before sending.
    public static func isValidResize(cols: Int, rows: Int) -> Bool {
        WireConstants.resizeRange.contains(cols) && WireConstants.resizeRange.contains(rows)
    }

    /// Mirrors the server's `attach.cwd` check: must start with "/"
    /// (src/protocol.ts:142-149; deeper normalisation stays server-side).
    public static func isAbsoluteCwd(_ candidate: String) -> Bool {
        candidate.hasPrefix("/")
    }
}
