{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://brubank.com/schemas/bds/0.1.0/schema.json",
  "title": "Brubank Design Schema (BDS)",
  "description": "Schema oficial v0.1.0 del protocolo Brubank Design Schema (pre-stable). Valida cualquier archivo .bds. Token syntax canónico: @<lib>/<category>/<key> (separador /, claves flat camelCase). Fuente de verdad — la documentación humana puede mentir, este archivo no.",

  "type": "object",
  "required": ["bds", "id", "name", "dependencies", "canvas"],
  "additionalProperties": false,

  "properties": {
    "bds": {
      "description": "Versión del protocolo BDS que cumple este documento (SemVer).",
      "type": "string",
      "pattern": "^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$"
    },

    "id": { "$ref": "#/$defs/uuid" },

    "name": { "type": "string", "minLength": 1 },

    "metadata": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "author":      { "type": "string" },
        "createdAt":   { "type": "string", "format": "date-time" },
        "updatedAt":   { "type": "string", "format": "date-time" },
        "description": { "type": "string" },
        "tags":        { "type": "array", "items": { "type": "string" }, "uniqueItems": true }
      }
    },

    "dependencies": {
      "description": "Mapa de alias-librería -> versión/path. Toda referencia @alias/... debe corresponder a una clave de este mapa.",
      "type": "object",
      "minProperties": 0,
      "propertyNames": {
        "pattern": "^[a-z][a-z0-9-]*[a-z0-9]$"
      },
      "additionalProperties": {
        "type": "string",
        "minLength": 1,
        "anyOf": [
          { "description": "SemVer exacta o range con prefijo ~/^", "pattern": "^[~^]?\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?(?:\\+[0-9A-Za-z.-]+)?$" },
          { "description": "Path local",     "pattern": "^file:.+$" },
          { "description": "URL HTTPS",      "pattern": "^https:\\/\\/.+$" }
        ]
      }
    },

    "canvas": {
      "type": "object",
      "additionalProperties": false,
      "required": ["children"],
      "properties": {
        "children": {
          "type": "array",
          "items": { "$ref": "#/$defs/topLevelNode" }
        }
      }
    }
  },

  "$defs": {

    "uuid": {
      "type": "string",
      "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"
    },

    "libAlias": {
      "type": "string",
      "pattern": "^[a-z][a-z0-9-]*[a-z0-9]$"
    },

    "tokenRef": {
      "description": "Referencia a un token: @<lib>/<category>/<key>. Categoría explícita (colors|textStyles|symbols). Clave flat camelCase (sin puntos, sin guiones bajos). La validación semántica (que el key exista en la categoría de la librería) la hace el loader.",
      "type": "string",
      "pattern": "^@[a-z][a-z0-9-]*\\/(colors|textStyles|symbols)\\/[a-z][a-zA-Z0-9]*$"
    },

    "componentRef": {
      "description": "Referencia a un componente de librería: @<lib>/<NombrePascalCase>. Sin segmento de categoría — los componentes se distinguen de los tokens por el case inicial uppercase del nombre.",
      "type": "string",
      "pattern": "^@[a-z][a-z0-9-]*\\/[A-Z][A-Za-z0-9]*$"
    },

    "size": {
      "description": "Medida de layout: número en px lógicos, fit_content o fill_container.",
      "oneOf": [
        { "type": "number", "minimum": 0 },
        { "type": "string", "enum": ["fit_content", "fill_container"] }
      ]
    },

    "padding": {
      "description": "Padding: número, [v,h] o [t,r,b,l].",
      "oneOf": [
        { "type": "number", "minimum": 0 },
        { "type": "array", "items": { "type": "number", "minimum": 0 }, "minItems": 2, "maxItems": 2 },
        { "type": "array", "items": { "type": "number", "minimum": 0 }, "minItems": 4, "maxItems": 4 }
      ]
    },

    "cornerRadius": {
      "oneOf": [
        { "type": "number", "minimum": 0 },
        { "type": "array", "items": { "type": "number", "minimum": 0 }, "minItems": 4, "maxItems": 4 }
      ]
    },

    "border": {
      "type": "object",
      "additionalProperties": false,
      "required": ["thickness", "color"],
      "properties": {
        "thickness": { "type": "number", "minimum": 0 },
        "color":     { "$ref": "#/$defs/tokenRef" },
        "style":     { "type": "string", "enum": ["solid", "dashed"], "default": "solid" }
      }
    },

    "action": {
      "type": "object",
      "required": ["kind"],
      "additionalProperties": false,
      "properties": {
        "kind":     { "type": "string", "enum": ["navigate", "back", "deeplink", "dismiss", "submit"] },
        "target":   { "type": "string" },
        "params":   { "type": "object", "additionalProperties": true },
        "endpoint": { "type": "string" },
        "payload":  { "type": "object", "additionalProperties": true }
      },
      "allOf": [
        {
          "if": { "properties": { "kind": { "const": "navigate" } } },
          "then": {
            "required": ["target"],
            "properties": {
              "target": { "type": "string", "pattern": "^\\/(?:[a-z0-9-]+|:[a-z][a-zA-Z0-9]*)(?:\\/(?:[a-z0-9-]+|:[a-z][a-zA-Z0-9]*))*$" }
            }
          }
        },
        {
          "if": { "properties": { "kind": { "const": "deeplink" } } },
          "then": {
            "required": ["target"],
            "properties": {
              "target": { "type": "string", "pattern": "^[a-z][a-z0-9+.-]*:\\/\\/.+$" }
            }
          }
        },
        {
          "if": { "properties": { "kind": { "enum": ["back", "dismiss"] } } },
          "then": {
            "not": { "anyOf": [
              { "required": ["target"]  },
              { "required": ["params"]  },
              { "required": ["endpoint"]},
              { "required": ["payload"] }
            ] }
          }
        }
      ]
    },

    "routeParams": {
      "type": "object",
      "additionalProperties": {
        "type": "object",
        "required": ["type"],
        "additionalProperties": false,
        "properties": {
          "type":     { "type": "string", "enum": ["string", "number", "boolean"] },
          "required": { "type": "boolean", "default": false }
        }
      }
    },

    "topLevelNode": {
      "description": "Nodos válidos en canvas.children: usualmente Screens.",
      "oneOf": [
        { "$ref": "#/$defs/screenNode" },
        { "$ref": "#/$defs/boxNode" }
      ]
    },

    "node": {
      "description": "Cualquier nodo del árbol: primitivas del core o referencia a un componente de librería.",
      "oneOf": [
        { "$ref": "#/$defs/screenNode" },
        { "$ref": "#/$defs/boxNode" },
        { "$ref": "#/$defs/textNode" },
        { "$ref": "#/$defs/imageNode" },
        { "$ref": "#/$defs/spacerNode" },
        { "$ref": "#/$defs/componentRefNode" }
      ]
    },

    "baseNode": {
      "type": "object",
      "required": ["uuid", "type"],
      "properties": {
        "uuid":    { "$ref": "#/$defs/uuid" },
        "type":    { "type": "string" },
        "name":    { "type": "string" },
        "visible": { "type": "boolean", "default": true }
      }
    },

    "screenNode": {
      "allOf": [
        { "$ref": "#/$defs/baseNode" },
        {
          "type": "object",
          "required": ["uuid", "type", "props"],
          "additionalProperties": false,
          "properties": {
            "uuid":    true,
            "type":    { "const": "Screen" },
            "name":    true,
            "visible": true,
            "props": {
              "type": "object",
              "required": ["route"],
              "additionalProperties": false,
              "properties": {
                "route": {
                  "type": "string",
                  "pattern": "^\\/(?:[a-z0-9-]+|:[a-z][a-zA-Z0-9]*)(?:\\/(?:[a-z0-9-]+|:[a-z][a-zA-Z0-9]*))*$"
                },
                "deeplink": {
                  "type": "string",
                  "pattern": "^[a-z][a-z0-9+.-]*:\\/\\/.+$"
                },
                "title":      { "type": "string" },
                "background": { "$ref": "#/$defs/tokenRef" },
                "safeArea":   { "type": "boolean", "default": true },
                "params":     { "$ref": "#/$defs/routeParams" }
              }
            },
            "children": {
              "type": "array",
              "items": { "$ref": "#/$defs/node" }
            }
          }
        }
      ]
    },

    "boxNode": {
      "allOf": [
        { "$ref": "#/$defs/baseNode" },
        {
          "type": "object",
          "required": ["uuid", "type"],
          "additionalProperties": false,
          "properties": {
            "uuid":    true,
            "type":    { "const": "Box" },
            "name":    true,
            "visible": true,
            "props": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "layout":         { "type": "string", "enum": ["vertical", "horizontal", "none"], "default": "vertical" },
                "gap":            { "type": "number", "minimum": 0, "default": 0 },
                "padding":        { "$ref": "#/$defs/padding" },
                "justifyContent": { "type": "string", "enum": ["start", "center", "end", "space_between", "space_around"], "default": "start" },
                "alignItems":     { "type": "string", "enum": ["start", "center", "end", "stretch"], "default": "start" },
                "width":          { "$ref": "#/$defs/size" },
                "height":         { "$ref": "#/$defs/size" },
                "x":              { "type": "number" },
                "y":              { "type": "number" },
                "background":     { "$ref": "#/$defs/tokenRef" },
                "cornerRadius":   { "$ref": "#/$defs/cornerRadius" },
                "border":         { "$ref": "#/$defs/border" },
                "opacity":        { "type": "number", "minimum": 0, "maximum": 1 }
              }
            },
            "children": {
              "type": "array",
              "items": { "$ref": "#/$defs/node" }
            }
          }
        }
      ]
    },

    "textNode": {
      "allOf": [
        { "$ref": "#/$defs/baseNode" },
        {
          "type": "object",
          "required": ["uuid", "type", "props"],
          "additionalProperties": false,
          "properties": {
            "uuid":    true,
            "type":    { "const": "Text" },
            "name":    true,
            "visible": true,
            "props": {
              "type": "object",
              "required": ["content", "textStyle", "color"],
              "additionalProperties": false,
              "properties": {
                "content":   { "type": "string" },
                "textStyle": { "$ref": "#/$defs/tokenRef" },
                "color":     { "$ref": "#/$defs/tokenRef" },
                "textAlign": { "type": "string", "enum": ["start", "center", "end"], "default": "start" },
                "maxLines":  { "type": "integer", "minimum": 1 },
                "ellipsize": { "type": "string", "enum": ["tail", "none"], "default": "none" }
              }
            }
          },
          "not": { "required": ["children"] }
        }
      ]
    },

    "imageNode": {
      "allOf": [
        { "$ref": "#/$defs/baseNode" },
        {
          "type": "object",
          "required": ["uuid", "type", "props"],
          "additionalProperties": false,
          "properties": {
            "uuid":    true,
            "type":    { "const": "Image" },
            "name":    true,
            "visible": true,
            "props": {
              "type": "object",
              "required": ["src"],
              "additionalProperties": false,
              "properties": {
                "src": {
                  "description": "URL HTTPS absoluta o token de librería @lib/assets.<key>.",
                  "oneOf": [
                    { "type": "string", "pattern": "^https:\\/\\/.+$" },
                    { "$ref": "#/$defs/tokenRef" }
                  ]
                },
                "alt":          { "type": "string" },
                "decorative":   { "type": "boolean", "default": false },
                "fit":          { "type": "string", "enum": ["cover", "contain", "fill", "none"], "default": "cover" },
                "width":        { "$ref": "#/$defs/size" },
                "height":       { "$ref": "#/$defs/size" },
                "cornerRadius": { "$ref": "#/$defs/cornerRadius" }
              },
              "allOf": [
                {
                  "description": "alt es obligatorio salvo decorative: true",
                  "if":   { "properties": { "decorative": { "const": true } }, "required": ["decorative"] },
                  "then": true,
                  "else": { "required": ["alt"] }
                }
              ]
            }
          },
          "not": { "required": ["children"] }
        }
      ]
    },

    "spacerNode": {
      "allOf": [
        { "$ref": "#/$defs/baseNode" },
        {
          "type": "object",
          "required": ["uuid", "type", "props"],
          "additionalProperties": false,
          "properties": {
            "uuid":    true,
            "type":    { "const": "Spacer" },
            "name":    true,
            "visible": true,
            "props": {
              "type": "object",
              "required": ["size"],
              "additionalProperties": false,
              "properties": {
                "size": {
                  "oneOf": [
                    { "type": "number", "minimum": 0 },
                    { "type": "string", "const": "fill_container" }
                  ]
                }
              }
            }
          },
          "not": { "required": ["children"] }
        }
      ]
    },

    "componentRefNode": {
      "description": "Nodo que referencia a un componente de librería externa. Las props son opacas para el core: se validan contra el manifest de la librería en otra capa.",
      "allOf": [
        { "$ref": "#/$defs/baseNode" },
        {
          "type": "object",
          "required": ["uuid", "type"],
          "additionalProperties": false,
          "properties": {
            "uuid":    true,
            "type":    { "$ref": "#/$defs/componentRef" },
            "name":    true,
            "visible": true,
            "props": {
              "type": "object",
              "additionalProperties": true
            },
            "children": {
              "description": "Solo válido si el componente declara slots en su manifest. El core acepta el array pero la validación de contenido la hace el loader.",
              "type": "array",
              "items": { "$ref": "#/$defs/node" }
            }
          }
        }
      ]
    }
  }
}
