{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://even.github.io/EDH_matchmaker/tournament-log.schema.json",
  "title": "EDH_matchmaker tournament log",
  "description": "Formal schema for the format described in docs/tournament-log-spec.md. Unknown top-level and nested fields are tolerated (additionalProperties: true) to match the spec's stated forward-compatibility stance.",
  "type": "object",
  "additionalProperties": true,
  "required": ["uid", "config", "players", "rounds"],
  "properties": {
    "format_version": {
      "type": "string",
      "description": "Absent means \"1.0\"."
    },
    "generator": {
      "type": "object",
      "additionalProperties": true,
      "required": ["name"],
      "properties": {
        "name": { "type": "string" },
        "version": { "type": "string" }
      }
    },
    "created_at": { "type": "string", "format": "date-time" },
    "updated_at": { "type": "string", "format": "date-time" },
    "uid": { "$ref": "#/$defs/uid" },
    "config": { "$ref": "#/$defs/config" },
    "players": {
      "type": "array",
      "items": { "$ref": "#/$defs/player" }
    },
    "rounds": {
      "type": "array",
      "items": { "$ref": "#/$defs/round" }
    }
  },
  "$defs": {
    "uid": {
      "type": "string",
      "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
    },
    "uidArray": {
      "type": "array",
      "items": { "$ref": "#/$defs/uid" },
      "uniqueItems": true
    },
    "stageOrTopCut": {
      "type": "integer",
      "enum": [0, 2, 4, 7, 8, 10, 13, 16, 40]
    },
    "config": {
      "type": "object",
      "additionalProperties": true,
      "required": [
        "pod_sizes", "allow_bye", "n_rounds", "max_byes",
        "auto_export", "standings_export", "top_cut"
      ],
      "properties": {
        "pod_sizes": {
          "type": "array",
          "items": { "type": "integer", "minimum": 1 },
          "minItems": 1
        },
        "allow_bye": { "type": "boolean" },
        "snake_pods": {
          "type": "boolean",
          "description": "Deprecated (read, never written): old logs used this to choose round 2's Swiss pairing. Round 2 is always PairingSnake now (CommanderRuleset.swiss_pairing_logic); an old snake_pods: false pins round 2 to PairingDefault via pairing_rounds instead."
        },
        "n_rounds": { "type": "integer", "minimum": 0 },
        "max_byes": { "type": "integer", "minimum": 0 },
        "auto_export": { "type": "boolean" },
        "standings_export": { "$ref": "#/$defs/standingsExport" },
        "global_wr_seats": {
          "type": "array",
          "items": { "type": "number" },
          "description": "CommanderRuleset only (CommanderConfiguration)."
        },
        "match_wr_seats": {
          "type": "array",
          "items": { "type": "number", "minimum": 0 },
          "description": "Mtg1v1Ruleset only (Mtg1v1Configuration)."
        },
        "match_draw_rate": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Mtg1v1Ruleset only (Mtg1v1Configuration)."
        },
        "top_cut": { "$ref": "#/$defs/stageOrTopCut" },
        "scoring_logic": { "type": "string" },
        "scoring_params": {
          "type": "object",
          "description": "Field names and defaults are owned by whichever class scoring_logic names - see the Scoring logic section of tournament-log-spec.md. Deliberately schema-free: a new scoring algorithm's params don't require a schema change here."
        },
        "ruleset": {
          "type": "string",
          "description": "Class name of the IRuleset owning this tournament's game rules - see the Rulesets section of tournament-log-spec.md."
        },
        "pairing_rounds": {
          "type": "array",
          "items": { "$ref": "#/$defs/pairingRound" }
        },
        "playoff_rounds": {
          "type": "object",
          "description": "Ruleset param overrides per playoff stage, keyed by stage value as a string (see stageOrTopCut). Deliberately schema-free per key: {\"ruleset_params\": {...}}."
        }
      }
    },
    "pairingRound": {
      "type": "object",
      "additionalProperties": true,
      "properties": {
        "logic": { "type": ["string", "null"] },
        "params": {
          "type": "object",
          "description": "Field names and defaults are owned by whichever pairing class `logic` names - deliberately schema-free."
        },
        "ruleset_params": {
          "type": "object",
          "description": "Field names and defaults are owned by the tournament's ruleset - deliberately schema-free."
        }
      }
    },
    "standingsExport": {
      "type": "object",
      "additionalProperties": true,
      "required": ["fields", "format", "dir"],
      "properties": {
        "fields": {
          "type": "array",
          "items": { "type": "integer", "minimum": 0, "maximum": 12 }
        },
        "format": { "type": "integer", "enum": [0, 2, 3] },
        "dir": { "type": "string" }
      }
    },
    "player": {
      "type": "object",
      "additionalProperties": true,
      "required": ["uid", "name", "decklist"],
      "properties": {
        "uid": { "$ref": "#/$defs/uid" },
        "name": { "type": "string" },
        "decklist": { "type": ["string", "null"] }
      }
    },
    "round": {
      "type": "object",
      "additionalProperties": true,
      "required": [
        "tour", "seq", "stage", "logic", "uid",
        "dropped", "disabled", "byes", "game_loss", "pods"
      ],
      "properties": {
        "tour": { "$ref": "#/$defs/uid" },
        "seq": { "type": "integer", "minimum": 0 },
        "stage": { "$ref": "#/$defs/stageOrTopCut" },
        "logic": { "type": "string" },
        "uid": { "$ref": "#/$defs/uid" },
        "dropped": { "$ref": "#/$defs/uidArray" },
        "disabled": { "$ref": "#/$defs/uidArray" },
        "byes": { "$ref": "#/$defs/uidArray" },
        "game_loss": { "$ref": "#/$defs/uidArray" },
        "pods": {
          "type": "array",
          "items": { "$ref": "#/$defs/pod" }
        }
      }
    },
    "pod": {
      "type": "object",
      "additionalProperties": true,
      "required": ["uid", "tour_round", "table", "cap", "result", "players"],
      "properties": {
        "uid": { "$ref": "#/$defs/uid" },
        "tour_round": { "$ref": "#/$defs/uid" },
        "table": { "type": "integer" },
        "cap": { "type": "integer", "minimum": 1 },
        "result": { "$ref": "#/$defs/uidArray" },
        "games": {
          "type": "array",
          "items": { "$ref": "#/$defs/game" }
        },
        "players": { "$ref": "#/$defs/uidArray" }
      }
    },
    "game": {
      "type": "object",
      "additionalProperties": true,
      "required": ["winners"],
      "properties": {
        "winners": {
          "type": "array",
          "items": { "$ref": "#/$defs/uid" },
          "uniqueItems": true,
          "minItems": 1
        }
      }
    }
  }
}
