{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.invalid/exam-card.schema.json",
  "title": "Exam Card Document",
  "description": "答题卡试卷配置 v1。坐标均为页面比例，原点左上角。",
  "type": "object",
  "additionalProperties": false,
  "required": ["schemaVersion", "unit", "paper", "markers", "questions"],
  "properties": {
    "schemaVersion": { "const": 1 },
    "unit": { "const": "ratio" },
    "paper": { "$ref": "#/$defs/paper" },
    "markers": {
      "type": "array",
      "minItems": 4,
      "maxItems": 4,
      "items": { "$ref": "#/$defs/marker" }
    },
    "blocks": {
      "type": "array",
      "maxItems": 200,
      "items": { "$ref": "#/$defs/textBlock" }
    },
    "questions": {
      "type": "array",
      "minItems": 1,
      "items": { "$ref": "#/$defs/question" }
    },
    "barcode": { "$ref": "#/$defs/barcode" },
    "answerKey": {
      "type": "object",
      "description": "key 是涂卡小题 id，value 是选项值",
      "additionalProperties": {
        "type": "string",
        "minLength": 1,
        "maxLength": 8
      }
    }
  },
  "$defs": {
    "ratio": {
      "type": "number",
      "minimum": 0,
      "maximum": 1
    },
    "positiveRatio": {
      "type": "number",
      "exclusiveMinimum": 0,
      "maximum": 1
    },
    "region": {
      "type": "object",
      "additionalProperties": false,
      "required": ["x", "y", "width", "height"],
      "properties": {
        "x": { "$ref": "#/$defs/ratio" },
        "y": { "$ref": "#/$defs/ratio" },
        "width": { "$ref": "#/$defs/positiveRatio" },
        "height": { "$ref": "#/$defs/positiveRatio" }
      }
    },
    "textBlock": {
      "type": "object",
      "additionalProperties": false,
      "required": ["id", "type", "region", "text"],
      "properties": {
        "id": { "type": "string", "minLength": 1, "maxLength": 64 },
        "type": { "const": "text" },
        "region": { "$ref": "#/$defs/region" },
        "text": { "type": "string", "minLength": 1, "maxLength": 5000 },
        "style": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "fontSize": { "type": "number", "exclusiveMinimum": 0, "maximum": 0.5 },
            "fontWeight": { "enum": ["normal", "bold"] },
            "textAlign": { "enum": ["left", "center", "right"] },
            "lineHeight": { "type": "number", "exclusiveMinimum": 0, "maximum": 5 },
            "color": { "type": "string", "pattern": "^#[0-9a-fA-F]{3,8}$" },
            "fontFamily": { "type": "string", "minLength": 1, "maxLength": 100 }
          }
        }
      }
    },
    "paper": {
      "type": "object",
      "additionalProperties": false,
      "required": ["name", "width", "height", "physical", "pdf"],
      "properties": {
        "name": { "type": "string", "minLength": 1, "maxLength": 50 },
        "width": { "type": "number", "exclusiveMinimum": 0 },
        "height": { "type": "number", "exclusiveMinimum": 0 },
        "physical": {
          "type": "object",
          "additionalProperties": false,
          "required": ["width", "height"],
          "properties": {
            "width": { "type": "number", "exclusiveMinimum": 0 },
            "height": { "type": "number", "exclusiveMinimum": 0 }
          }
        },
        "pdf": {
          "type": "object",
          "additionalProperties": false,
          "required": ["width", "height"],
          "properties": {
            "width": { "type": "number", "exclusiveMinimum": 0 },
            "height": { "type": "number", "exclusiveMinimum": 0 }
          }
        }
      }
    },
    "marker": {
      "type": "object",
      "additionalProperties": false,
      "required": ["id", "x", "y", "size"],
      "properties": {
        "id": {
          "enum": ["top-left", "top-right", "bottom-left", "bottom-right"]
        },
        "x": { "$ref": "#/$defs/ratio" },
        "y": { "$ref": "#/$defs/ratio" },
        "size": { "$ref": "#/$defs/positiveRatio" }
      }
    },
    "choice": {
      "type": "object",
      "additionalProperties": false,
      "required": ["value", "region"],
      "properties": {
        "value": { "type": "string", "minLength": 1, "maxLength": 8 },
        "region": { "$ref": "#/$defs/region" }
      }
    },
    "markQuestion": {
      "type": "object",
      "additionalProperties": false,
      "required": ["id", "type", "region", "choices"],
      "properties": {
        "id": { "type": "string", "minLength": 1, "maxLength": 64 },
        "displayNumber": { "type": "integer", "minimum": 1 },
        "type": { "const": "mark" },
        "region": { "$ref": "#/$defs/region" },
        "choices": {
          "type": "array",
          "minItems": 2,
          "maxItems": 8,
          "items": { "$ref": "#/$defs/choice" }
        }
      }
    },
    "otherQuestion": {
      "type": "object",
      "additionalProperties": false,
      "required": ["id", "type", "region"],
      "properties": {
        "id": { "type": "string", "minLength": 1, "maxLength": 64 },
        "displayNumber": { "type": "integer", "minimum": 1 },
        "type": { "const": "other" },
        "region": { "$ref": "#/$defs/region" }
      }
    },
    "question": {
      "oneOf": [
        { "$ref": "#/$defs/markQuestion" },
        { "$ref": "#/$defs/otherQuestion" }
      ]
    },
    "length": {
      "type": "object",
      "additionalProperties": false,
      "required": ["unit", "x", "y"],
      "properties": {
        "unit": { "enum": ["mm", "ratio"] },
        "x": { "type": "number" },
        "y": { "type": "number" }
      }
    },
    "size": {
      "type": "object",
      "additionalProperties": false,
      "required": ["unit", "width", "height"],
      "properties": {
        "unit": { "enum": ["mm", "ratio"] },
        "width": { "type": "number", "exclusiveMinimum": 0 },
        "height": { "type": "number", "exclusiveMinimum": 0 }
      }
    },
    "barcode": {
      "type": "object",
      "additionalProperties": false,
      "required": ["value", "anchor", "offset", "size"],
      "properties": {
        "id": { "type": "string", "minLength": 1, "maxLength": 64 },
        "type": { "type": "string", "minLength": 1, "maxLength": 32 },
        "value": { "type": "string", "minLength": 1, "maxLength": 256 },
        "anchor": {
          "enum": ["top-left", "top-right", "bottom-left", "bottom-right"]
        },
        "offset": { "$ref": "#/$defs/length" },
        "size": { "$ref": "#/$defs/size" },
        "minSize": {
          "type": "object",
          "additionalProperties": false,
          "required": ["width", "height"],
          "properties": {
            "width": { "type": "number", "exclusiveMinimum": 0 },
            "height": { "type": "number", "exclusiveMinimum": 0 }
          }
        },
        "label": { "type": "string", "maxLength": 64 },
        "labelOffset": { "$ref": "#/$defs/length" },
        "valueOffset": { "$ref": "#/$defs/length" },
        "render": { "type": "object" }
      }
    }
  }
}
