const std = @import("std");

/// Validation errors for queue operations
pub const ValidationError = error{
    MissingJobName,
    InvalidCommitId,
    InvalidSnapshotId,
    InvalidResourceLimits,
    DuplicateJobName,
    InvalidPriority,
};

/// Validation result
pub const ValidationResult = struct {
    valid: bool,
    errors: std.ArrayList([]const u8),

    pub fn init(allocator: std.mem.Allocator) ValidationResult {
        return .{
            .valid = true,
            .errors = std.ArrayList([]const u8).init(allocator),
        };
    }

    pub fn deinit(self: *ValidationResult, allocator: std.mem.Allocator) void {
        for (self.errors.items) |err| {
            allocator.free(err);
        }
        self.errors.deinit(allocator);
    }

    pub fn addError(self: *ValidationResult, allocator: std.mem.Allocator, msg: []const u8) void {
        self.valid = false;
        const copy = allocator.dupe(u8, msg) catch return;
        self.errors.append(copy) catch {
            allocator.free(copy);
        };
    }
};

/// Validate job name format
pub fn validateJobName(name: []const u8) bool {
    if (name.len == 0 or name.len > 128) return false;

    for (name) |c| {
        if (!std.ascii.isAlphanumeric(c) and c != '_' and c != '-' and c != '.') {
            return false;
        }
    }
    return true;
}

/// Validate commit ID format (40 character hex)
pub fn validateCommitId(id: []const u8) bool {
    if (id.len != 40) return false;
    for (id) |c| {
        if (!std.ascii.isHex(c)) return false;
    }
    return true;
}

/// Validate snapshot ID format
pub fn validateSnapshotId(id: []const u8) bool {
    if (id.len == 0 or id.len > 64) return false;
    for (id) |c| {
        if (!std.ascii.isAlphanumeric(c) and c != '_' and c != '-' and c != '.') {
            return false;
        }
    }
    return true;
}

/// Validate resource limits
pub fn validateResources(cpu: u8, memory: u8, gpu: u8) ValidationError!void {
    if (cpu == 0 or cpu > 128) {
        return error.InvalidResourceLimits;
    }
    if (memory == 0 or memory > 1024) {
        return error.InvalidResourceLimits;
    }
    if (gpu > 16) {
        return error.InvalidResourceLimits;
    }
}

/// Validate priority value (1-10)
pub fn validatePriority(priority: u8) ValidationError!void {
    if (priority < 1 or priority > 10) {
        return error.InvalidPriority;
    }
}

/// Full validation for job template
pub fn validateJobTemplate(
    allocator: std.mem.Allocator,
    job_names: []const []const u8,
    commit_id: ?[]const u8,
    cpu: u8,
    memory: u8,
    gpu: u8,
) !ValidationResult {
    var result = ValidationResult.init(allocator);
    errdefer result.deinit(allocator);

    // Check job names
    if (job_names.len == 0) {
        result.addError(allocator, "At least one job name is required");
        return result;
    }

    // Check for duplicates
    var seen = std.StringHashMap(void).init(allocator);
    defer seen.deinit();

    for (job_names) |name| {
        if (!validateJobName(name)) {
            const msg = try std.fmt.allocPrint(allocator, "Invalid job name: {s}", .{name});
            result.addError(allocator, msg);
            allocator.free(msg);
        }

        if (seen.contains(name)) {
            const msg = try std.fmt.allocPrint(allocator, "Duplicate job name: {s}", .{name});
            result.addError(allocator, msg);
            allocator.free(msg);
        } else {
            try seen.put(name, {});
        }
    }

    // Validate commit ID if provided
    if (commit_id) |id| {
        if (!validateCommitId(id)) {
            result.addError(allocator, "Invalid commit ID format (expected 40 character hex)");
        }
    }

    // Validate resources
    validateResources(cpu, memory, gpu) catch {
        result.addError(allocator, "Invalid resource limits");
    };

    return result;
}

/// Print validation errors
pub fn printValidationErrors(result: ValidationResult, json: bool) void {
    if (json) {
        std.debug.print("{{\"success\":false,\"command\":\"queue.validate\",\"errors\":[", .{});
        for (result.errors.items, 0..) |err, i| {
            if (i > 0) std.debug.print(",", .{});
            std.debug.print("\"{s}\"", .{err});
        }
        std.debug.print("]}}\n", .{});
    } else {
        std.debug.print("Validation failed:\n", .{});
        for (result.errors.items) |err| {
            std.debug.print("  - {s}\n", .{err});
        }
    }
}
