# MCP Server Validators
# Tools, prompts, resources, capabilities, and sampling validation

let constraints = import "../constraints/constraints.toml" in
let common = import "./common-validator.ncl" in
let string_val = import "./string-validator.ncl" in

{
  # Validate max concurrent tool executions
  ValidMaxConcurrentTools = fun count =>
    common.ValidRange
      constraints.mcp_server.tools.max_concurrent.min
      constraints.mcp_server.tools.max_concurrent.max
      count,

  # Validate tool execution timeout in milliseconds
  ValidToolTimeout = fun timeout =>
    common.ValidRange
      constraints.mcp_server.tools.timeout.min
      constraints.mcp_server.tools.timeout.max
      timeout,

  # Validate max resource size in bytes
  ValidMaxResourceSize = fun size =>
    common.ValidRange
      constraints.mcp_server.resources.max_size.min
      constraints.mcp_server.resources.max_size.max
      size,

  # Validate resource cache TTL in seconds
  ValidResourceCacheTtl = fun ttl =>
    common.ValidRange
      constraints.mcp_server.resources.cache_ttl.min
      constraints.mcp_server.resources.cache_ttl.max
      ttl,

  # Validate max custom prompt templates
  ValidMaxPromptTemplates = fun count =>
    common.ValidRange
      constraints.mcp_server.prompts.max_templates.min
      constraints.mcp_server.prompts.max_templates.max
      count,

  # Validate max tokens for sampling
  ValidMaxSamplingTokens = fun tokens =>
    common.ValidRange
      constraints.mcp_server.sampling.max_tokens.min
      constraints.mcp_server.sampling.max_tokens.max
      tokens,

  # Validate temperature value (0.0-2.0 typical range)
  ValidTemperature = fun temperature =>
    if temperature < 0.0 then
      std.contract.blame_with_message "Temperature must be >= 0.0" temperature
    else if temperature > 2.0 then
      std.contract.blame_with_message "Temperature must be <= 2.0" temperature
    else
      temperature,

  # Validate tool name
  ValidToolName = fun name =>
    string_val.ValidIdentifier name,

  # Validate prompt template name
  ValidPromptTemplateName = fun name =>
    string_val.ValidIdentifier name,

  # Validate resource type
  ValidResourceType = fun resource_type =>
    string_val.ValidCategoryName resource_type,

  # Validate tool category
  ValidToolCategory = fun category =>
    string_val.ValidCategoryName category,

  # Validate protocol version
  ValidProtocolVersion = fun version =>
    if version == "" then
      std.contract.blame_with_message "Protocol version cannot be empty" version
    else if !std.string.matches "^[0-9]+(\\.[0-9]+)*$" version then
      std.contract.blame_with_message
        "Protocol version must be semantic version (e.g., 1.0, 2.1.3)"
        version
    else
      version,

  # Validate tool definition completeness
  ValidToolDefinition = fun tool =>
    if tool.name == null || tool.name == "" then
      std.contract.blame_with_message "Tool must have a non-empty name" tool
    else if tool.description == null || tool.description == "" then
      std.contract.blame_with_message "Tool must have a non-empty description" tool
    else
      tool,

  # Validate prompt template structure
  ValidPromptTemplate = fun prompt =>
    if prompt.name == null || prompt.name == "" then
      std.contract.blame_with_message "Prompt must have a non-empty name" prompt
    else
      prompt,

  # Validate resource path
  ValidResourcePath = fun path =>
    string_val.ValidFilesystemPath path,

  # Validate MCP capabilities configuration
  ValidCapabilitiesConfig = fun capabilities =>
    if !capabilities.tools.enabled &&
       !capabilities.prompts.enabled &&
       !capabilities.resources.enabled then
      std.contract.blame_with_message
        "At least one capability (tools, prompts, or resources) must be enabled"
        capabilities
    else
      capabilities,

  # Validate template engine
  ValidTemplateEngine = fun engine =>
    let valid_engines = ['jinja2, 'tera, 'handlebars] in
    common.ValidEnum valid_engines engine,

  # Validate sampling model identifier
  ValidSamplingModel = fun model =>
    string_val.ValidIdentifier model,
}
