{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://developers.mouve.it/schemas/venue-setup-v1.json",
  "title": "Mouve venue setup (v1)",
  "description": "One venue with its spaces, opening hours, closures and display prices. Written by an agent as venue-setup.json and uploaded by the owner at https://mouve.it/venues/new. Times are HH:MM in the venue's local time. Money is an integer in minor units (cents) with an ISO 4217 currency.",
  "type": "object",
  "additionalProperties": false,
  "required": ["schema_version", "venue", "spaces", "hours"],
  "properties": {
    "schema_version": { "const": "venue-setup-v1" },
    "venue": { "$ref": "#/$defs/venue" },
    "spaces": {
      "type": "array",
      "minItems": 1,
      "maxItems": 200,
      "items": { "$ref": "#/$defs/space" }
    },
    "hours": {
      "type": "array",
      "minItems": 1,
      "maxItems": 2000,
      "items": { "$ref": "#/$defs/hoursRow" }
    },
    "closures": {
      "type": "array",
      "maxItems": 500,
      "items": { "$ref": "#/$defs/closure" }
    },
    "price_rules": {
      "type": "array",
      "maxItems": 500,
      "items": { "$ref": "#/$defs/priceRule" }
    }
  },
  "$defs": {
    "time": {
      "type": "string",
      "description": "Local time, 24-hour HH:MM. 24:00 is allowed as a closing time.",
      "pattern": "^(([01][0-9]|2[0-3]):[0-5][0-9]|24:00)$"
    },
    "date": {
      "type": "string",
      "description": "Local calendar date, YYYY-MM-DD.",
      "pattern": "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$"
    },
    "weekday": {
      "enum": ["mon", "tue", "wed", "thu", "fri", "sat", "sun"]
    },
    "key": {
      "type": "string",
      "description": "Your own stable id for a space inside this file, for example court-1.",
      "pattern": "^[a-z0-9][a-z0-9_-]{0,39}$"
    },
    "venue": {
      "type": "object",
      "additionalProperties": false,
      "required": ["name", "address", "timezone", "currency", "slot_minutes"],
      "properties": {
        "name": { "type": "string", "minLength": 2, "maxLength": 120 },
        "description": { "type": "string", "maxLength": 1000 },
        "kind": {
          "enum": ["gym", "courts", "studio", "outdoor", "pool", "other"]
        },
        "sports": {
          "type": "array",
          "maxItems": 20,
          "items": { "type": "string", "minLength": 2, "maxLength": 40 }
        },
        "address": {
          "type": "object",
          "additionalProperties": false,
          "required": ["line1", "city", "country"],
          "properties": {
            "line1": { "type": "string", "minLength": 2, "maxLength": 200 },
            "city": { "type": "string", "minLength": 1, "maxLength": 100 },
            "postal_code": { "type": "string", "maxLength": 20 },
            "country": {
              "type": "string",
              "description": "ISO 3166-1 alpha-2.",
              "pattern": "^[A-Z]{2}$"
            }
          }
        },
        "timezone": {
          "type": "string",
          "description": "IANA time zone name, for example Europe/Tallinn.",
          "pattern": "^[A-Za-z_]+(/[A-Za-z0-9_+-]+)+$"
        },
        "currency": {
          "type": "string",
          "description": "ISO 4217.",
          "pattern": "^[A-Z]{3}$"
        },
        "slot_minutes": { "enum": [15, 30, 45, 60, 90, 120] },
        "website": {
          "type": "string",
          "description": "Public website. The owner proves control of its domain before the venue goes public.",
          "format": "uri",
          "pattern": "^https://",
          "maxLength": 300
        },
        "contact": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "email": { "type": "string", "format": "email", "maxLength": 200 },
            "phone": { "type": "string", "pattern": "^\\+[0-9 ()-]{6,24}$" }
          }
        }
      }
    },
    "space": {
      "type": "object",
      "additionalProperties": false,
      "required": ["key", "name", "sport"],
      "properties": {
        "key": { "$ref": "#/$defs/key" },
        "name": { "type": "string", "minLength": 1, "maxLength": 80 },
        "kind": { "enum": ["court", "room", "zone", "lane"] },
        "sport": { "type": "string", "minLength": 2, "maxLength": 40 },
        "surface": { "type": "string", "maxLength": 40 },
        "indoor": { "type": "boolean" },
        "capacity": { "type": "integer", "minimum": 1, "maximum": 1000 }
      }
    },
    "hoursRow": {
      "type": "object",
      "additionalProperties": false,
      "required": ["weekday", "opens", "closes"],
      "properties": {
        "space_keys": {
          "type": "array",
          "description": "Omit for the whole venue.",
          "minItems": 1,
          "items": { "$ref": "#/$defs/key" }
        },
        "weekday": { "$ref": "#/$defs/weekday" },
        "opens": { "$ref": "#/$defs/time" },
        "closes": { "$ref": "#/$defs/time" }
      }
    },
    "closure": {
      "type": "object",
      "additionalProperties": false,
      "required": ["from_date", "to_date"],
      "properties": {
        "space_keys": {
          "type": "array",
          "description": "Omit for the whole venue.",
          "minItems": 1,
          "items": { "$ref": "#/$defs/key" }
        },
        "from_date": { "$ref": "#/$defs/date" },
        "to_date": { "$ref": "#/$defs/date" },
        "reason": { "type": "string", "maxLength": 200 }
      }
    },
    "priceRule": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "name",
        "weekdays",
        "from",
        "to",
        "amount_minor",
        "currency"
      ],
      "properties": {
        "name": { "type": "string", "minLength": 1, "maxLength": 80 },
        "space_keys": {
          "type": "array",
          "description": "Omit for every space.",
          "minItems": 1,
          "items": { "$ref": "#/$defs/key" }
        },
        "weekdays": {
          "type": "array",
          "minItems": 1,
          "maxItems": 7,
          "uniqueItems": true,
          "items": { "$ref": "#/$defs/weekday" }
        },
        "from": { "$ref": "#/$defs/time" },
        "to": { "$ref": "#/$defs/time" },
        "amount_minor": {
          "type": "integer",
          "minimum": 0,
          "description": "Price of one slot in minor units. 2400 with EUR is 24.00 EUR."
        },
        "currency": { "type": "string", "pattern": "^[A-Z]{3}$" }
      }
    }
  }
}
