{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://muxen.io/schemas/ais-targets.json",
  "title": "AIS Targets",
  "description": "Merged AIS data from multiple NMEA 2000 PGNs (compact format)",
  "type": "object",
  "properties": {
    "data": {
      "type": "object",
      "description": "AIS data container",
      "properties": {
        "aisTargets": {
          "type": "object",
          "description": "Vessel targets keyed by MMSI",
          "additionalProperties": {
            "$ref": "#/$defs/aisTarget"
          }
        },
        "atons": {
          "type": "object",
          "description": "Aids to Navigation keyed by MMSI",
          "additionalProperties": {
            "$ref": "#/$defs/aton"
          }
        },
        "sarAircraft": {
          "type": "object",
          "description": "SAR aircraft keyed by MMSI",
          "additionalProperties": {
            "$ref": "#/$defs/sarAircraft"
          }
        },
        "safetyMessages": {
          "type": "array",
          "description": "Safety-related messages",
          "items": {
            "$ref": "#/$defs/safetyMessage"
          }
        }
      },
      "required": ["aisTargets", "atons", "sarAircraft", "safetyMessages"]
    },
    "metadata": {
      "$ref": "#/$defs/metadata"
    }
  },
  "required": ["data", "metadata"],
  "$defs": {
    "metadata": {
      "type": "object",
      "description": "Report-level metadata (root only)",
      "properties": {
        "rxDate": {
          "type": "string",
          "format": "date-time",
          "description": "ISO8601 timestamp when report was generated"
        },
        "rxTimestamp": {
          "type": "integer",
          "description": "Unix timestamp when report was generated"
        },
        "expireAfterSec": {
          "type": "integer",
          "description": "Time-to-live in seconds"
        }
      },
      "required": ["rxDate", "rxTimestamp", "expireAfterSec"]
    },
    "dynamics": {
      "type": "object",
      "description": "Vessel dynamics (motion)",
      "properties": {
        "cog": {
          "type": "number",
          "minimum": 0,
          "maximum": 360,
          "description": "Course over ground in degrees (0.1° resolution)"
        },
        "sog": {
          "type": "number",
          "minimum": 0,
          "description": "Speed over ground in knots (0.01 kn resolution)"
        },
        "heading": {
          "type": "number",
          "minimum": 0,
          "maximum": 360,
          "description": "True heading in degrees"
        },
        "rateOfTurn": {
          "type": "number",
          "description": "Rate of turn in degrees/minute"
        }
      }
    },
    "identity": {
      "type": "object",
      "description": "Vessel identification",
      "properties": {
        "vesselName": {
          "type": "string",
          "maxLength": 20,
          "description": "Vessel name"
        },
        "callSign": {
          "type": "string",
          "maxLength": 7,
          "description": "Radio call sign"
        },
        "imo": {
          "type": "integer",
          "description": "IMO ship identification number (Class A only)"
        },
        "shipType": {
          "type": "integer",
          "minimum": 0,
          "maximum": 99,
          "description": "Ship and cargo type code"
        }
      }
    },
    "dimensions": {
      "type": "object",
      "description": "Vessel dimensions",
      "properties": {
        "length": {
          "type": "number",
          "minimum": 0,
          "description": "Overall length in meters"
        },
        "beam": {
          "type": "number",
          "minimum": 0,
          "description": "Beam (width) in meters"
        }
      }
    },
    "voyage": {
      "type": "object",
      "description": "Voyage data (Class A only)",
      "properties": {
        "destination": {
          "type": "string",
          "maxLength": 20,
          "description": "Destination port/location"
        },
        "eta": {
          "type": "string",
          "format": "date-time",
          "description": "Estimated time of arrival"
        },
        "draught": {
          "type": "number",
          "minimum": 0,
          "description": "Current draught in meters"
        },
        "navStatus": {
          "type": "integer",
          "minimum": 0,
          "maximum": 15,
          "description": "Navigation status code"
        }
      }
    },
    "trackPoint": {
      "type": "array",
      "description": "[latitude, longitude] coordinate pair",
      "items": { "type": "number" },
      "minItems": 2,
      "maxItems": 2
    },
    "aisTarget": {
      "type": "object",
      "description": "AIS vessel target",
      "properties": {
        "mmsi": {
          "type": "integer",
          "description": "Maritime Mobile Service Identity"
        },
        "aisClass": {
          "type": "string",
          "enum": ["A", "B", "B+"],
          "description": "AIS equipment class"
        },
        "identity": {
          "$ref": "#/$defs/identity"
        },
        "dimensions": {
          "$ref": "#/$defs/dimensions"
        },
        "lat": {
          "type": "number",
          "minimum": -90,
          "maximum": 90,
          "description": "Latitude in decimal degrees"
        },
        "lon": {
          "type": "number",
          "minimum": -180,
          "maximum": 180,
          "description": "Longitude in decimal degrees"
        },
        "dynamics": {
          "$ref": "#/$defs/dynamics"
        },
        "voyage": {
          "$ref": "#/$defs/voyage"
        },
        "track": {
          "type": "array",
          "description": "Historical track as [lat, lon] tuples",
          "items": {
            "$ref": "#/$defs/trackPoint"
          }
        },
        "cpaNm": {
          "type": "number",
          "description": "Closest Point of Approach in nautical miles"
        },
        "tcpaSec": {
          "type": "number",
          "description": "Time to CPA in seconds (negative = passed)"
        },
        "rxTs": {
          "type": "integer",
          "description": "Receive timestamp (Unix seconds)"
        }
      },
      "required": ["mmsi", "aisClass", "lat", "lon", "rxTs"]
    },
    "aton": {
      "type": "object",
      "description": "Aid to Navigation",
      "properties": {
        "mmsi": {
          "type": "integer",
          "description": "AtoN MMSI (starts with 99)"
        },
        "name": {
          "type": "string",
          "maxLength": 20,
          "description": "AtoN name"
        },
        "atonType": {
          "type": "integer",
          "minimum": 0,
          "maximum": 31,
          "description": "Type of AtoN code"
        },
        "offPosition": {
          "type": "boolean"
        },
        "virtualAton": {
          "type": "boolean"
        },
        "lat": {
          "type": "number",
          "minimum": -90,
          "maximum": 90
        },
        "lon": {
          "type": "number",
          "minimum": -180,
          "maximum": 180
        },
        "rxTs": {
          "type": "integer",
          "description": "Receive timestamp (Unix seconds)"
        }
      },
      "required": ["mmsi", "name", "lat", "lon", "rxTs"]
    },
    "sarAircraft": {
      "type": "object",
      "description": "Search and Rescue aircraft",
      "properties": {
        "mmsi": {
          "type": "integer",
          "description": "SAR MMSI (starts with 111)"
        },
        "lat": {
          "type": "number",
          "minimum": -90,
          "maximum": 90
        },
        "lon": {
          "type": "number",
          "minimum": -180,
          "maximum": 180
        },
        "alt": {
          "type": "number",
          "minimum": 0,
          "description": "Altitude in meters"
        },
        "dynamics": {
          "$ref": "#/$defs/dynamics"
        },
        "rxTs": {
          "type": "integer",
          "description": "Receive timestamp (Unix seconds)"
        }
      },
      "required": ["mmsi", "lat", "lon", "alt", "rxTs"]
    },
    "safetyMessage": {
      "type": "object",
      "description": "Safety-related message",
      "properties": {
        "sourceMmsi": {
          "type": "integer",
          "description": "Sender MMSI"
        },
        "destinationMmsi": {
          "type": "integer",
          "description": "Recipient MMSI (if addressed)"
        },
        "text": {
          "type": "string",
          "maxLength": 162,
          "description": "Safety message text"
        },
        "rxTs": {
          "type": "integer",
          "description": "Receive timestamp (Unix seconds)"
        }
      },
      "required": ["sourceMmsi", "text", "rxTs"]
    }
  }
}
