{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://sestava.app/format/schemas/plan.schema.json",
  "title": "Sestava plan (sestava.plan/1)",
  "type": "object",
  "required": [
    "format",
    "name"
  ],
  "properties": {
    "format": {
      "type": "string",
      "pattern": "^sestava\\.plan/1(\\.[0-9]+)?$"
    },
    "name": {
      "$ref": "#/$defs/nonBlank"
    },
    "author": {
      "$ref": "#/$defs/optionalString"
    },
    "id": {
      "type": "string",
      "pattern": "^[A-Za-z0-9_-]{1,64}$"
    },
    "version": {
      "type": "integer",
      "minimum": 1,
      "maximum": 9007199254740991
    },
    "category": {
      "enum": [
        "strength",
        "hiit",
        "mobility",
        "core",
        "cardio",
        "recovery",
        "climbing",
        "yoga",
        "boxing"
      ]
    },
    "note": {
      "anyOf": [
        {
          "type": "null"
        },
        {
          "type": "string",
          "maxLength": 500
        }
      ]
    },
    "progression": {
      "$ref": "#/$defs/progression"
    },
    "weeks": {
      "type": "array",
      "minItems": 1,
      "items": {
        "$ref": "#/$defs/week"
      }
    },
    "blocks": {
      "type": "array",
      "minItems": 1,
      "items": {
        "$ref": "#/$defs/block"
      }
    }
  },
  "dependentRequired": {
    "id": [
      "version"
    ],
    "version": [
      "id"
    ]
  },
  "oneOf": [
    {
      "required": [
        "weeks"
      ],
      "not": {
        "required": [
          "blocks"
        ],
        "properties": {
          "blocks": true
        }
      },
      "properties": {
        "weeks": true
      }
    },
    {
      "required": [
        "blocks"
      ],
      "not": {
        "required": [
          "weeks"
        ],
        "properties": {
          "weeks": true
        }
      },
      "properties": {
        "blocks": true
      }
    }
  ],
  "$defs": {
    "nonBlank": {
      "type": "string",
      "pattern": "\\S"
    },
    "nullableString": {
      "anyOf": [
        {
          "type": "null"
        },
        {
          "type": "string",
          "pattern": "\\S"
        }
      ]
    },
    "optionalString": {
      "anyOf": [
        {
          "type": "null"
        },
        {
          "type": "string"
        }
      ]
    },
    "seconds": {
      "type": "integer",
      "minimum": 1,
      "maximum": 86400
    },
    "rounds": {
      "type": "integer",
      "minimum": 1,
      "maximum": 1000
    },
    "count": {
      "type": "integer",
      "minimum": 1,
      "maximum": 10000
    },
    "progression": {
      "description": "Reserved (#408); semantics in #407. Readers that do not apply progression ignore it; field types are provisional.",
      "type": "object",
      "properties": {
        "rule": {
          "$ref": "#/$defs/nonBlank"
        },
        "step": {
          "$ref": "#/$defs/count"
        },
        "range": {
          "type": "array",
          "minItems": 2,
          "maxItems": 2,
          "items": {
            "$ref": "#/$defs/count"
          }
        },
        "ladder": {
          "$ref": "#/$defs/nonBlank"
        },
        "stepBackAfter": {
          "$ref": "#/$defs/rounds"
        },
        "deloadEvery": {
          "$ref": "#/$defs/rounds"
        }
      }
    },
    "week": {
      "type": "object",
      "required": [
        "days"
      ],
      "properties": {
        "days": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/day"
          }
        }
      }
    },
    "day": {
      "type": "object",
      "required": [
        "name",
        "blocks"
      ],
      "properties": {
        "name": {
          "$ref": "#/$defs/nonBlank"
        },
        "blocks": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/block"
          }
        }
      }
    },
    "block": {
      "type": "object",
      "required": [
        "section",
        "items"
      ],
      "properties": {
        "section": {
          "$ref": "#/$defs/nonBlank"
        },
        "mode": {
          "enum": [
            "normal",
            "superset",
            "amrap",
            "fortime"
          ]
        },
        "cap": {
          "$ref": "#/$defs/seconds"
        },
        "bell": {
          "type": "boolean"
        },
        "warn": {
          "$ref": "#/$defs/seconds"
        },
        "rounds": {
          "$ref": "#/$defs/rounds"
        },
        "items": {
          "type": "array",
          "minItems": 1
        }
      },
      "dependentSchemas": {
        "warn": {
          "required": [
            "bell"
          ],
          "properties": {
            "bell": {
              "const": true
            }
          }
        }
      },
      "if": {
        "required": [
          "mode"
        ],
        "properties": {
          "mode": {
            "enum": [
              "amrap",
              "fortime"
            ]
          }
        }
      },
      "then": {
        "required": [
          "cap"
        ],
        "properties": {
          "items": {
            "items": {
              "$ref": "#/$defs/blockExercise"
            },
            "type": "array"
          },
          "cap": true
        },
        "not": {
          "anyOf": [
            {
              "required": [
                "bell"
              ],
              "properties": {
                "bell": true
              }
            },
            {
              "required": [
                "warn"
              ],
              "properties": {
                "warn": true
              }
            },
            {
              "required": [
                "rounds"
              ],
              "properties": {
                "rounds": true
              }
            }
          ]
        }
      },
      "else": {
        "not": {
          "anyOf": [
            {
              "required": [
                "cap"
              ],
              "properties": {
                "cap": true
              }
            }
          ]
        },
        "if": {
          "required": [
            "mode"
          ],
          "properties": {
            "mode": {
              "const": "superset"
            }
          }
        },
        "then": {
          "properties": {
            "items": {
              "minItems": 2,
              "items": {
                "$ref": "#/$defs/strengthItem"
              },
              "type": "array"
            }
          },
          "not": {
            "anyOf": [
              {
                "required": [
                  "bell"
                ],
                "properties": {
                  "bell": true
                }
              },
              {
                "required": [
                  "warn"
                ],
                "properties": {
                  "warn": true
                }
              },
              {
                "required": [
                  "rounds"
                ],
                "properties": {
                  "rounds": true
                }
              }
            ]
          }
        },
        "else": {
          "properties": {
            "items": {
              "items": {
                "$ref": "#/$defs/item"
              },
              "type": "array"
            }
          }
        }
      }
    },
    "item": {
      "oneOf": [
        {
          "$ref": "#/$defs/timedItem"
        },
        {
          "$ref": "#/$defs/strengthItem"
        },
        {
          "$ref": "#/$defs/restItem"
        },
        {
          "$ref": "#/$defs/hangItem"
        }
      ]
    },
    "timedItem": {
      "type": "object",
      "required": [
        "exercise",
        "time"
      ],
      "properties": {
        "exercise": {
          "$ref": "#/$defs/nonBlank"
        },
        "time": {
          "$ref": "#/$defs/seconds"
        },
        "sides": {
          "$ref": "#/$defs/sides"
        },
        "cue": {
          "$ref": "#/$defs/optionalString"
        },
        "load": {
          "$ref": "#/$defs/nullableString"
        },
        "image": {
          "$ref": "#/$defs/optionalString"
        }
      },
      "not": {
        "anyOf": [
          {
            "required": [
              "sets"
            ],
            "properties": {
              "sets": true
            }
          },
          {
            "required": [
              "reps"
            ],
            "properties": {
              "reps": true
            }
          },
          {
            "required": [
              "rest"
            ],
            "properties": {
              "rest": true
            }
          },
          {
            "required": [
              "tempo"
            ],
            "properties": {
              "tempo": true
            }
          },
          {
            "required": [
              "prep"
            ],
            "properties": {
              "prep": true
            }
          },
          {
            "required": [
              "hang"
            ],
            "properties": {
              "hang": true
            }
          },
          {
            "required": [
              "off"
            ],
            "properties": {
              "off": true
            }
          },
          {
            "required": [
              "repeats"
            ],
            "properties": {
              "repeats": true
            }
          },
          {
            "required": [
              "setRest"
            ],
            "properties": {
              "setRest": true
            }
          },
          {
            "required": [
              "grip"
            ],
            "properties": {
              "grip": true
            }
          },
          {
            "required": [
              "edge"
            ],
            "properties": {
              "edge": true
            }
          },
          {
            "required": [
              "progression"
            ],
            "properties": {
              "progression": true
            }
          }
        ]
      }
    },
    "strengthItem": {
      "type": "object",
      "required": [
        "exercise",
        "sets",
        "reps"
      ],
      "properties": {
        "exercise": {
          "$ref": "#/$defs/nonBlank"
        },
        "sets": {
          "$ref": "#/$defs/count"
        },
        "reps": {
          "anyOf": [
            {
              "$ref": "#/$defs/count"
            },
            {
              "type": "array",
              "minItems": 1,
              "items": {
                "$ref": "#/$defs/count"
              }
            }
          ]
        },
        "rest": {
          "$ref": "#/$defs/seconds"
        },
        "sides": {
          "$ref": "#/$defs/sides"
        },
        "tempo": {
          "$ref": "#/$defs/optionalString"
        },
        "cue": {
          "$ref": "#/$defs/optionalString"
        },
        "load": {
          "anyOf": [
            {
              "$ref": "#/$defs/nullableString"
            },
            {
              "type": "array",
              "minItems": 1,
              "items": {
                "$ref": "#/$defs/nonBlank"
              }
            }
          ]
        },
        "image": {
          "$ref": "#/$defs/optionalString"
        },
        "progression": {
          "$ref": "#/$defs/progression"
        }
      },
      "not": {
        "anyOf": [
          {
            "required": [
              "time"
            ],
            "properties": {
              "time": true
            }
          },
          {
            "required": [
              "prep"
            ],
            "properties": {
              "prep": true
            }
          },
          {
            "required": [
              "hang"
            ],
            "properties": {
              "hang": true
            }
          },
          {
            "required": [
              "off"
            ],
            "properties": {
              "off": true
            }
          },
          {
            "required": [
              "repeats"
            ],
            "properties": {
              "repeats": true
            }
          },
          {
            "required": [
              "setRest"
            ],
            "properties": {
              "setRest": true
            }
          },
          {
            "required": [
              "grip"
            ],
            "properties": {
              "grip": true
            }
          },
          {
            "required": [
              "edge"
            ],
            "properties": {
              "edge": true
            }
          }
        ]
      }
    },
    "restItem": {
      "type": "object",
      "required": [
        "rest"
      ],
      "properties": {
        "rest": {
          "$ref": "#/$defs/seconds"
        }
      },
      "not": {
        "anyOf": [
          {
            "required": [
              "exercise"
            ],
            "properties": {
              "exercise": true
            }
          },
          {
            "required": [
              "time"
            ],
            "properties": {
              "time": true
            }
          },
          {
            "required": [
              "sets"
            ],
            "properties": {
              "sets": true
            }
          },
          {
            "required": [
              "reps"
            ],
            "properties": {
              "reps": true
            }
          },
          {
            "required": [
              "sides"
            ],
            "properties": {
              "sides": true
            }
          },
          {
            "required": [
              "tempo"
            ],
            "properties": {
              "tempo": true
            }
          },
          {
            "required": [
              "cue"
            ],
            "properties": {
              "cue": true
            }
          },
          {
            "required": [
              "load"
            ],
            "properties": {
              "load": true
            }
          },
          {
            "required": [
              "image"
            ],
            "properties": {
              "image": true
            }
          },
          {
            "required": [
              "prep"
            ],
            "properties": {
              "prep": true
            }
          },
          {
            "required": [
              "hang"
            ],
            "properties": {
              "hang": true
            }
          },
          {
            "required": [
              "off"
            ],
            "properties": {
              "off": true
            }
          },
          {
            "required": [
              "repeats"
            ],
            "properties": {
              "repeats": true
            }
          },
          {
            "required": [
              "setRest"
            ],
            "properties": {
              "setRest": true
            }
          },
          {
            "required": [
              "grip"
            ],
            "properties": {
              "grip": true
            }
          },
          {
            "required": [
              "edge"
            ],
            "properties": {
              "edge": true
            }
          },
          {
            "required": [
              "progression"
            ],
            "properties": {
              "progression": true
            }
          }
        ]
      }
    },
    "zeroSeconds": {
      "type": "integer",
      "minimum": 0,
      "maximum": 86400
    },
    "repeats": {
      "type": "integer",
      "minimum": 1,
      "maximum": 1000
    },
    "sides": {
      "enum": [
        1,
        2
      ]
    },
    "hangItem": {
      "type": "object",
      "required": [
        "exercise",
        "hang",
        "repeats"
      ],
      "properties": {
        "exercise": {
          "$ref": "#/$defs/nonBlank"
        },
        "prep": {
          "$ref": "#/$defs/zeroSeconds"
        },
        "hang": {
          "$ref": "#/$defs/seconds"
        },
        "off": {
          "$ref": "#/$defs/zeroSeconds"
        },
        "repeats": {
          "$ref": "#/$defs/repeats"
        },
        "sets": {
          "$ref": "#/$defs/count"
        },
        "setRest": {
          "$ref": "#/$defs/zeroSeconds"
        },
        "grip": {
          "$ref": "#/$defs/optionalString"
        },
        "edge": {
          "$ref": "#/$defs/optionalString"
        },
        "cue": {
          "$ref": "#/$defs/optionalString"
        },
        "load": {
          "$ref": "#/$defs/nullableString"
        },
        "image": {
          "$ref": "#/$defs/optionalString"
        }
      },
      "not": {
        "anyOf": [
          {
            "required": [
              "time"
            ],
            "properties": {
              "time": true
            }
          },
          {
            "required": [
              "reps"
            ],
            "properties": {
              "reps": true
            }
          },
          {
            "required": [
              "rest"
            ],
            "properties": {
              "rest": true
            }
          },
          {
            "required": [
              "sides"
            ],
            "properties": {
              "sides": true
            }
          },
          {
            "required": [
              "tempo"
            ],
            "properties": {
              "tempo": true
            }
          },
          {
            "required": [
              "progression"
            ],
            "properties": {
              "progression": true
            }
          }
        ]
      }
    },
    "blockExercise": {
      "type": "object",
      "required": [
        "exercise",
        "reps"
      ],
      "properties": {
        "exercise": {
          "$ref": "#/$defs/nonBlank"
        },
        "reps": {
          "anyOf": [
            {
              "$ref": "#/$defs/count"
            },
            {
              "$ref": "#/$defs/nonBlank"
            }
          ]
        },
        "cue": {
          "$ref": "#/$defs/optionalString"
        },
        "load": {
          "$ref": "#/$defs/nullableString"
        }
      },
      "not": {
        "anyOf": [
          {
            "required": [
              "time"
            ],
            "properties": {
              "time": true
            }
          },
          {
            "required": [
              "sets"
            ],
            "properties": {
              "sets": true
            }
          },
          {
            "required": [
              "rest"
            ],
            "properties": {
              "rest": true
            }
          },
          {
            "required": [
              "sides"
            ],
            "properties": {
              "sides": true
            }
          },
          {
            "required": [
              "tempo"
            ],
            "properties": {
              "tempo": true
            }
          },
          {
            "required": [
              "image"
            ],
            "properties": {
              "image": true
            }
          },
          {
            "required": [
              "prep"
            ],
            "properties": {
              "prep": true
            }
          },
          {
            "required": [
              "hang"
            ],
            "properties": {
              "hang": true
            }
          },
          {
            "required": [
              "off"
            ],
            "properties": {
              "off": true
            }
          },
          {
            "required": [
              "repeats"
            ],
            "properties": {
              "repeats": true
            }
          },
          {
            "required": [
              "setRest"
            ],
            "properties": {
              "setRest": true
            }
          },
          {
            "required": [
              "grip"
            ],
            "properties": {
              "grip": true
            }
          },
          {
            "required": [
              "edge"
            ],
            "properties": {
              "edge": true
            }
          },
          {
            "required": [
              "progression"
            ],
            "properties": {
              "progression": true
            }
          }
        ]
      }
    }
  }
}
