{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://anpfiff.app/schema/anpfiff-dataset-v3.schema.json",
  "title": "Anpfiff-Datensatz (Formatversion 3)",
  "description": "Struktur-Schema für das öffentliche .anpfiff-Datensatzformat, Version 3. Dieses Schema prüft Typen, Pflichtfelder und Wertebereiche pro Feld. Es kann KEINE Cross-Referenzen (leagueId/teamId müssen auf existierende Einträge zeigen), KEINE globale ID-Eindeutigkeit, KEIN 18-Team-je-Liga-Raster, KEINE Mindestkadergröße (11 Spieler/Team) und KEIN Auslandsliga-Const-ID-Raster ausdrücken — diese Regeln sind ausschließlich in `lib/services/import_validation.dart` (Dart) implementiert und normativ in SPEC.de.md/SPEC.en.md beschrieben. Ein Dokument, das dieses Schema erfüllt, ist noch nicht zwingend importierbar.",
  "type": "object",
  "required": ["leagues", "teams", "players"],
  "additionalProperties": true,
  "properties": {
    "version": {
      "description": "Formatversion. Fehlt das Feld, wird 2 angenommen. Nur 2 (nur Inlandsligen) oder 3 (darf zusätzlich die sechs Auslandsligen tragen) werden akzeptiert; jeder andere Wert wird abgelehnt.",
      "type": "integer",
      "enum": [2, 3],
      "default": 2
    },
    "exportedAt": {
      "description": "ISO-8601-Zeitstempel des Exports. Rein informativ, wird beim Import komplett ignoriert.",
      "type": "string"
    },
    "leagues": {
      "description": "Alle Ligen des Datensatzes. Mindestens 2 Inlandsligen erforderlich (siehe SPEC: Mindestanzahl und Maximalwerte hängen von `version` ab und sind hier nicht ausdrückbar). Jede Liga muss von Schema-Ebene aus gesehen aus genau 18 Teams bestehen (Cross-Check, nicht hier prüfbar).",
      "type": "array",
      "minItems": 1,
      "items": { "$ref": "#/$defs/league" }
    },
    "teams": {
      "description": "Alle Vereine des Datensatzes, referenzieren `leagueId`.",
      "type": "array",
      "minItems": 1,
      "items": { "$ref": "#/$defs/team" }
    },
    "players": {
      "description": "Alle Spieler des Datensatzes, referenzieren `teamId`.",
      "type": "array",
      "items": { "$ref": "#/$defs/player" }
    },
    "relations": {
      "description": "Optionale Team-Beziehungen (Rivalen/Freunde). Fehlt das Feld oder ist es leer, werden keine Beziehungen importiert.",
      "type": "array",
      "items": { "$ref": "#/$defs/relation" }
    }
  },
  "$defs": {
    "league": {
      "type": "object",
      "required": ["id", "name", "level"],
      "additionalProperties": true,
      "properties": {
        "id": {
          "description": "Eindeutige Liga-ID. Inlandsligen: < 10. Auslandsligen (nur Version 3): exakt eine der IDs 10–15 (siehe SPEC für die feste Zuordnung Land↔ID). Dieses Schema kann nicht prüfen, dass genau diese sechs Werte plus deren jeweils komplettes 18er-Team-Raster verwendet werden.",
          "type": "integer",
          "minimum": 0
        },
        "name": {
          "description": "Anzeigename der Liga.",
          "type": "string",
          "minLength": 1
        },
        "level": {
          "description": "Ligastufe. 1 = erste Liga, 2 = zweite Liga. Auslandsligen werden immer flach simuliert und tragen level 1.",
          "type": "integer",
          "minimum": 1
        }
      }
    },
    "team": {
      "type": "object",
      "required": [
        "id",
        "name",
        "color1",
        "color2",
        "budget",
        "formation",
        "leagueId",
        "fixtureName"
      ],
      "additionalProperties": true,
      "properties": {
        "id": {
          "description": "Eindeutige Team-ID, global über den gesamten Datensatz. Inlandsvereine: < 1000. Auslandsvereine (nur Version 3): müssen exakt auf dem festen Const-ID-Raster ihrer Liga liegen (siehe SPEC, Abschnitt Auslandsligen-Raster) — nicht durch dieses Schema prüfbar.",
          "type": "integer",
          "minimum": 0
        },
        "name": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100
        },
        "shortName": {
          "description": "Kurzname/Abkürzung. Optional, Default: leerer String.",
          "type": "string"
        },
        "color1": {
          "description": "Haupttrikotfarbe als ARGB-Integer (0xAARRGGBB).",
          "type": "integer"
        },
        "color2": {
          "description": "Sekundärfarbe als ARGB-Integer (0xAARRGGBB).",
          "type": "integer"
        },
        "budget": {
          "description": "Transferbudget in Tausend Euro.",
          "type": "integer"
        },
        "formation": {
          "description": "Formation, z. B. \"4-4-2\".",
          "type": "string",
          "minLength": 1
        },
        "lineup": {
          "description": "JSON-kodiertes Array von Spieler-IDs der Startelf (als String, z. B. \"[1,2,3]\"). Optional, Default \"[]\".",
          "type": "string"
        },
        "bench": {
          "description": "JSON-kodiertes Array von Spieler-IDs der Bank (als String). Optional, Default \"[]\".",
          "type": "string"
        },
        "leagueId": {
          "description": "Muss auf eine `leagues[].id` im selben Datensatz zeigen (Cross-Referenz, nicht durch dieses Schema prüfbar).",
          "type": "integer"
        },
        "city": {
          "description": "Vereinsstadt. Optional, Default: leerer String.",
          "type": "string"
        },
        "fixtureName": {
          "description": "Name für Spielplan-/Tabellenanzeigen.",
          "type": "string",
          "minLength": 1
        },
        "badgeId": {
          "description": "Index des Wappen-Assets (1–54) oder Referenz auf ein mitgeliefertes `badges/badge_<badgeId>.webp` im ZIP-Container. Optional, Default: die eigene Team-ID (Fallback auf Legacy-Zuordnung).",
          "type": "integer"
        },
        "stadiumName": {
          "description": "Stadionname. Optional; fehlt/leer → kein Stadion-Datensatz wird angelegt.",
          "type": "string"
        },
        "stadiumLevel": {
          "description": "Stadionstufe 1–5. Optional; fehlt der Wert, wird er deterministisch aus `budget` abgeleitet.",
          "type": "integer",
          "minimum": 1,
          "maximum": 5
        },
        "stadiumCapacity": {
          "description": "Optionale manuelle Zuschauerkapazität. Fehlt sie, wird die Kapazität aus der Stadionstufe berechnet.",
          "type": "integer",
          "minimum": 0
        },
        "fanCharacter": {
          "description": "Optionaler Fan-Charakter.",
          "type": "string",
          "enum": ["treu", "launisch", "leidenschaftlich", "kritisch"]
        },
        "fanbaseSize": {
          "description": "Optionale Fanbasis-Größe, 1 (Nische) bis 5 (Massenverein).",
          "type": "integer",
          "minimum": 1,
          "maximum": 5
        },
        "foundingYear": {
          "description": "Optionales Gründungsjahr.",
          "type": "integer"
        }
      }
    },
    "player": {
      "type": "object",
      "required": [
        "id",
        "name",
        "positionIndex",
        "technique",
        "fitness",
        "form",
        "talent",
        "age",
        "marketValue",
        "teamId"
      ],
      "additionalProperties": true,
      "properties": {
        "id": {
          "description": "Eindeutige Spieler-ID, global über den gesamten Datensatz.",
          "type": "integer",
          "minimum": 0
        },
        "name": {
          "type": "string",
          "minLength": 1,
          "maxLength": 100
        },
        "positionIndex": {
          "description": "Position: 0=Torwart, 1=Abwehr, 2=Mittelfeld, 3=Sturm.",
          "type": "integer",
          "minimum": 0,
          "maximum": 3
        },
        "secondaryPositionIndex": {
          "description": "Optionale Zweitposition, gleiche Kodierung wie positionIndex.",
          "type": "integer",
          "minimum": 0,
          "maximum": 3
        },
        "technique": {
          "description": "Technik-Attribut, 1–99.",
          "type": "integer",
          "minimum": 1,
          "maximum": 99
        },
        "fitness": {
          "description": "Kondition-Attribut, 1–99.",
          "type": "integer",
          "minimum": 1,
          "maximum": 99
        },
        "form": {
          "description": "Form-Attribut, 1–99.",
          "type": "integer",
          "minimum": 1,
          "maximum": 99
        },
        "talent": {
          "description": "Talent-Attribut, 1–99.",
          "type": "integer",
          "minimum": 1,
          "maximum": 99
        },
        "age": {
          "description": "Alter in Jahren.",
          "type": "integer",
          "minimum": 0
        },
        "marketValue": {
          "description": "Marktwert in Tausend Euro.",
          "type": "integer",
          "minimum": 0
        },
        "wage": {
          "description": "Jahresgehalt in Tausend Euro. Optional; fehlt der Wert oder ist er 0, wird marketValue / 8 (kSalaryDivisor) als Fallback verwendet.",
          "type": "integer",
          "minimum": 0
        },
        "contractEndYear": {
          "description": "Jahr, in dem der Vertrag ausläuft. Optional; fehlt der Wert, wird das aktuelle Saisonjahr + 2 angenommen.",
          "type": "integer"
        },
        "nationality": {
          "description": "Nationalität als Freitext-Landesname. Optional, Default: \"Deutschland\".",
          "type": "string"
        },
        "teamId": {
          "description": "Muss auf eine `teams[].id` im selben Datensatz zeigen (Cross-Referenz, nicht durch dieses Schema prüfbar).",
          "type": "integer"
        },
        "constitution": {
          "description": "Konstitutions-Attribut (Verletzungsanfälligkeit), 0–100. Optional, Default 50.",
          "type": "integer",
          "minimum": 0,
          "maximum": 100
        },
        "leadership": {
          "description": "Führungsstärke-Attribut, 0–100. Optional, Default 50.",
          "type": "integer",
          "minimum": 0,
          "maximum": 100
        },
        "nerves": {
          "description": "Nerven-Attribut, 0–100. Optional, Default 50.",
          "type": "integer",
          "minimum": 0,
          "maximum": 100
        },
        "sportingNationId": {
          "description": "Optionale Referenz auf eine Nationalmannschafts-ID (kNations). Fehlt der Wert oder ist die ID unbekannt, bleibt das Feld leer und wird später neu zugewiesen.",
          "type": "integer"
        },
        "eligibleNationIds": {
          "description": "Optionales JSON-kodiertes Array wählbarer Nationalmannschafts-IDs (als String).",
          "type": "string"
        }
      }
    },
    "relation": {
      "type": "object",
      "required": ["teamId", "relatedTeamId", "relationType"],
      "additionalProperties": true,
      "properties": {
        "teamId": { "type": "integer" },
        "relatedTeamId": { "type": "integer" },
        "relationType": {
          "type": "string",
          "enum": ["rival", "friend"]
        }
      }
    }
  }
}
