{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "https://www.anguskit.com/schema/angusmeter/plugins/angus-grpc.json",
  "type": "object",
  "properties": {
    "host": {
      "type": "string",
      "description": "gRPC server host; supports ${var} interpolation"
    },
    "port": {
      "type": "integer",
      "minimum": 1,
      "maximum": 65535
    },
    "service": {
      "type": "string",
      "description": "Fully-qualified service name, e.g. helloworld.Greeter"
    },
    "method": {
      "type": "string",
      "description": "RPC method name"
    },
    "callType": {
      "type": "string",
      "enum": [
        "UNARY",
        "SERVER_STREAMING",
        "CLIENT_STREAMING",
        "BIDIRECTIONAL_STREAMING"
      ],
      "default": "UNARY"
    },
    "requestBody": {
      "type": "string",
      "description": "JSON request message (UNARY / SERVER_STREAMING); supports ${var} interpolation"
    },
    "requestMessages": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Sequence of JSON messages (CLIENT_STREAMING / BIDIRECTIONAL_STREAMING)"
    },
    "interMessageDelayMs": {
      "type": "integer",
      "minimum": 0,
      "maximum": 60000,
      "default": 0,
      "description": "Delay between streamed request messages (ms, 0-60000)"
    },
    "metadata": {
      "type": "object",
      "additionalProperties": {
        "type": "string"
      },
      "description": "gRPC metadata headers. Plain keys use ASCII marshaller (supports ${var} interpolation). Keys ending with '-bin' use binary marshaller — provide Base64-encoded value."
    },
    "tls": {
      "type": "object",
      "description": "TLS configuration (object-only). All fields are mapped through cloud.xcan.angus.spec.model.TlsConfig; keystore/truststore or PEM certificate pairs enable mutual TLS.",
      "properties": {
        "enabled": {
          "type": "boolean",
          "default": false
        },
        "trustAll": {
          "type": "boolean",
          "default": false,
          "description": "Trust all certificates (test only) - uses InsecureTrustManagerFactory"
        },
        "verifyHostname": {
          "type": "boolean",
          "default": true,
          "description": "When false, gRPC authority is overridden to bypass hostname verification"
        },
        "keystorePath": {
          "type": "string",
          "description": "Path to client keystore (JKS/PKCS12) for mTLS. Store format is inferred from the extension."
        },
        "keystorePassword": {
          "type": "string",
          "description": "Client keystore password.",
          "writeOnly": true
        },
        "truststorePath": {
          "type": "string",
          "description": "Path to custom trust store (JKS/PKCS12)."
        },
        "truststorePassword": {
          "type": "string",
          "description": "Trust store password.",
          "writeOnly": true
        },
        "certPath": {
          "type": "string",
          "description": "Path to PEM client certificate (with keyPath for mTLS)."
        },
        "keyPath": {
          "type": "string",
          "description": "Path to PEM PKCS#8 private key (used with certPath)."
        },
        "keyPassword": {
          "type": "string",
          "description": "Password for encrypted PEM private key (PKCS#8 EncryptedPrivateKeyInfo).",
          "writeOnly": true
        },
        "caPath": {
          "type": "string",
          "description": "Path to PEM CA bundle used as trust store (alternative to truststorePath)."
        },
        "protocols": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Allowed TLS protocol versions (e.g. [\"TLSv1.3\"])."
        },
        "ciphers": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Allowed cipher suites."
        }
      },
      "additionalProperties": false
    },
    "keepAlive": {
      "type": "object",
      "description": "Channel keep-alive settings",
      "properties": {
        "timeSeconds": {
          "type": "integer",
          "minimum": 1,
          "description": "Send keep-alive ping every N seconds"
        },
        "timeoutSeconds": {
          "type": "integer",
          "minimum": 1,
          "description": "Seconds to wait for keep-alive ack before closing"
        },
        "withoutCalls": {
          "type": "boolean",
          "default": false,
          "description": "Send keep-alive pings even without active RPC"
        }
      },
      "additionalProperties": false
    },
    "timeout": {
      "type": "integer",
      "minimum": 1,
      "maximum": 300,
      "default": 30,
      "description": "RPC deadline in seconds (1-300)"
    },
    "maxInboundMessageBytes": {
      "type": "integer",
      "minimum": 0,
      "description": "Max inbound message size in bytes; 0 or unset uses gRPC default (4 MB)"
    },
    "protoDescriptor": {
      "type": "string",
      "description": "Path to FileDescriptorSet binary or 'base64:<encoded>' for serialized FileDescriptorSet. Required for JSON↔Protobuf encoding."
    },
    "compression": {
      "type": "string",
      "enum": [
        "identity",
        "gzip"
      ],
      "description": "Per-call gRPC message compression algo; 'identity' means no compression"
    },
    "serviceConfig": {
      "type": "object",
      "description": "gRPC service config JSON (retry policy, LB policy, method config, etc.) passed to ManagedChannelBuilder#defaultServiceConfig"
    },
    "assertions": {
      "type": "array",
      "description": "Optional step-level assertions evaluated against the gRPC sample result (see GrpcConfigValidator).",
      "items": {
        "$ref": "#/definitions/grpcAssertion"
      }
    },
    "extractors": {
      "type": "array",
      "description": "Optional extractors from the gRPC response (see GrpcConfigValidator).",
      "items": {
        "$ref": "#/definitions/grpcExtractor"
      }
    },
    "maxDurationSeconds": {
      "type": "integer",
      "minimum": 1,
      "description": "Maximum duration in seconds for streaming/SSE mode. Only used with the stream() API."
    }
  },
  "required": [
    "host",
    "port",
    "service",
    "method"
  ],
  "additionalProperties": true,
  "definitions": {
    "grpcAssertion": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "type": {
          "type": "string",
          "enum": [
            "BODY_CONTAINS",
            "BODY_EQUALS",
            "BODY_JSON_PATH",
            "STATUS_CODE",
            "RESPONSE_TIME"
          ]
        },
        "operator": {
          "type": "string"
        },
        "expected": {
          "description": "Expected value for the assertion"
        },
        "expression": {
          "type": "string"
        },
        "enabled": {
          "type": "boolean"
        }
      },
      "required": [
        "type"
      ]
    },
    "grpcExtractor": {
      "type": "object",
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "JSON_PATH",
            "REGEX",
            "RESPONSE_CODE",
            "RESPONSE_TIME"
          ]
        },
        "expression": {
          "type": "string"
        },
        "variable": {
          "type": "string"
        },
        "defaultValue": {
          "type": "string"
        }
      },
      "required": [
        "type",
        "variable"
      ],
      "allOf": [
        {
          "if": {
            "properties": {
              "type": {
                "enum": [
                  "JSON_PATH",
                  "REGEX"
                ]
              }
            }
          },
          "then": {
            "required": [
              "expression"
            ]
          }
        }
      ]
    }
  }
}
