openapi: "3.0.3"
info:
  title: "TipSharks API"
  version: "1.0.0"
  description: |
    TipSharks unified API — racing ratings and predictions platform.

    This contract defines the domain models and endpoints shared across all three
    TipSharks services:
      - **tab-api-ingest**: Near-realtime horse racing data ingestion
      - **tipsharks-elo-api**: Elo-style multi-entity ratings engine + REST API
      - **tipsharks-client**: Mobile racing tips app (thoroughbred, harness, greyhound)

    All dates and datetimes are in ISO 8601 format.

servers:
  - url: http://localhost:8080
    description: Local development
  - url: https://api.tipsharks.example.com
    description: Production

paths:
  /health:
    get:
      operationId: healthCheck
      summary: Health check endpoint
      tags:
        - Health
      responses:
        "200":
          description: Service is healthy
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
                  timestamp:
                    type: string
                    format: date-time
                required:
                  - status
                  - timestamp

  /v1/meetings:
    get:
      operationId: listMeetings
      summary: List all meetings (optionally filtered by date)
      tags:
        - Meetings
      parameters:
        - name: date
          in: query
          description: Filter by meeting date (YYYY-MM-DD)
          required: false
          schema:
            type: string
            format: date
        - name: country
          in: query
          description: Filter by country (AUS, NZ)
          required: false
          schema:
            type: string
            enum:
              - AUS
              - NZ
        - name: category
          in: query
          description: Filter by racing category
          required: false
          schema:
            type: string
            enum:
              - T
              - H
              - G
      responses:
        "200":
          description: List of meetings
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Meeting"

  /v1/races:
    get:
      operationId: listRaces
      summary: List races with optional filters
      tags:
        - Races
      parameters:
        - name: meetingId
          in: query
          description: Filter by meeting ID
          required: false
          schema:
            type: string
        - name: status
          in: query
          description: Filter by race status
          required: false
          schema:
            type: string
            enum:
              - scheduled
              - open
              - closed
              - final
      responses:
        "200":
          description: List of races
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Race"

  /v1/races/{id}:
    get:
      operationId: getRace
      summary: Get a single race by ID
      tags:
        - Races
      parameters:
        - name: id
          in: path
          required: true
          description: Race ID
          schema:
            type: string
      responses:
        "200":
          description: Race details
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Race"
        "404":
          description: Race not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /v1/races/{id}/runners:
    get:
      operationId: getRaceRunners
      summary: List runners for a race
      tags:
        - Races
        - Runners
      parameters:
        - name: id
          in: path
          required: true
          description: Race ID
          schema:
            type: string
      responses:
        "200":
          description: List of runners for the race
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Runner"
        "404":
          description: Race not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /v1/races/{id}/predictions:
    get:
      operationId: getRacePredictions
      summary: Get predictions for a race
      tags:
        - Predictions
      parameters:
        - name: id
          in: path
          required: true
          description: Race ID
          schema:
            type: string
      responses:
        "200":
          description: Predictions for the race
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Prediction"
        "404":
          description: Race not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /v1/ratings/{entityType}:
    get:
      operationId: listRatings
      summary: List ratings by entity type
      tags:
        - Ratings
      parameters:
        - name: entityType
          in: path
          required: true
          description: Type of entity (horse, driver, trainer)
          schema:
            type: string
            enum:
              - horse
              - driver
              - trainer
        - name: entityId
          in: query
          description: Filter by specific entity ID
          required: false
          schema:
            type: string
        - name: asOfDate
          in: query
          description: Filter ratings as of this date (YYYY-MM-DD)
          required: false
          schema:
            type: string
            format: date
      responses:
        "200":
          description: List of ratings
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Rating"

  /v1/tips/generate:
    post:
      operationId: generateTips
      summary: Generate tips for a race
      tags:
        - Tips
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - raceId
              properties:
                raceId:
                  type: string
                  description: The race ID to generate tips for
                strategy:
                  type: string
                  description: Optional tip generation strategy
      responses:
        "200":
          description: Generated tips for the race
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Tip"
        "400":
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "404":
          description: Race not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

components:
  schemas:
    Error:
      type: object
      description: Standard error response
      properties:
        code:
          type: string
          description: Machine-readable error code
        message:
          type: string
          description: Human-readable error message
        details:
          type: string
          description: Additional error context
      required:
        - code
        - message

    Meeting:
      type: object
      description: A racing meeting (race card at a venue on a given date)
      properties:
        id:
          type: string
          description: Unique identifier for the meeting
        date:
          type: string
          format: date
          description: Meeting date (YYYY-MM-DD)
        venue:
          type: string
          description: Venue / track name
        country:
          type: string
          description: Country code
          enum:
            - AUS
            - NZ
        category:
          type: string
          description: Racing category
          enum:
            - T
            - H
            - G
          x-enum-descriptions:
            - T = Thoroughbred
            - H = Harness
            - G = Greyhound
        trackCondition:
          type: string
          description: Track condition (e.g. Good, Soft, Heavy)
        races:
          type: array
          description: Races scheduled at this meeting
          items:
            $ref: "#/components/schemas/Race"
      required:
        - id
        - date
        - venue
        - country
        - category

    Race:
      type: object
      description: A single race within a meeting
      properties:
        id:
          type: string
          description: Unique identifier for the race
        meetingId:
          type: string
          description: ID of the parent meeting
        raceNumber:
          type: integer
          description: Race number on the card
        startTime:
          type: string
          format: date-time
          description: Scheduled start time (ISO 8601)
        distance:
          type: integer
          description: Race distance in meters
        status:
          type: string
          description: Current race status
          enum:
            - scheduled
            - open
            - closed
            - final
        class:
          type: string
          description: Race class / grade
        conditions:
          type: string
          description: Race conditions / restrictions
        prizeMoney:
          type: integer
          description: Total prize money in local currency (cents or whole units)
        runners:
          type: array
          description: Runners declared in this race
          items:
            $ref: "#/components/schemas/Runner"
      required:
        - id
        - meetingId
        - raceNumber
        - startTime
        - distance
        - status

    Runner:
      type: object
      description: A runner (horse/greyhound) or starter entry in a race
      properties:
        id:
          type: string
          description: Unique identifier for the runner entry
        raceId:
          type: string
          description: ID of the race this runner is in
        number:
          type: integer
          description: Saddle cloth / rug number
        name:
          type: string
          description: Horse / greyhound name
        barrier:
          type: integer
          description: Barrier / gate position
        rider:
          type: string
          description: Jockey (thoroughbred) or driver (harness)
        trainer:
          type: string
          description: Trainer name
        weight:
          type: number
          description: Assigned weight (kg)
          format: float
        form:
          type: string
          description: Recent form string (e.g. 1-3x25)
        scratched:
          type: boolean
          description: Whether the runner has been scratched
          default: false
        winProbability:
          type: number
          description: Estimated win probability (0-1)
          format: float
          minimum: 0
          maximum: 1
        placeProbability:
          type: number
          description: Estimated place probability (0-1)
          format: float
          minimum: 0
          maximum: 1
      required:
        - id
        - raceId
        - number
        - name
        - barrier

    Dividend:
      type: object
      description: A dividend paid for a tote betting pool
      properties:
        id:
          type: string
          description: Unique identifier for this dividend record
        raceId:
          type: string
          description: ID of the race
        tote:
          type: string
          description: Tote pool type
          enum:
            - win
            - place
            - quinella
            - exacta
            - trifecta
            - first_four
            - double
            - treble
        productName:
          type: string
          description: Human-readable product name
        dividend:
          type: number
          description: Dividend payout amount
          format: float
        poolSize:
          type: number
          description: Total pool size (optional)
          format: float
        positions:
          type: array
          description: Finishing positions this dividend applies to (e.g. [1] for win, [1,2] for quinella)
          items:
            type: integer
          example:
            - 1
            - 2
      required:
        - id
        - raceId
        - tote
        - productName
        - dividend
        - positions

    Rating:
      type: object
      description: An Elo-style rating for a racing entity
      properties:
        entityId:
          type: string
          description: Unique identifier for the rated entity
        entityType:
          type: string
          description: Type of entity being rated
          enum:
            - horse
            - driver
            - trainer
        rating:
          type: number
          description: Elo rating value
          format: float
        rd:
          type: number
          description: Rating deviation (measure of uncertainty)
          format: float
        asOfDate:
          type: string
          format: date
          description: Date this rating was computed (YYYY-MM-DD)
      required:
        - entityId
        - entityType
        - rating
        - rd
        - asOfDate

    Prediction:
      type: object
      description: A win/place probability prediction for a runner in a race
      properties:
        raceId:
          type: string
          description: ID of the race
        runnerId:
          type: string
          description: ID of the runner
        winProbability:
          type: number
          description: Predicted win probability (0-1)
          format: float
          minimum: 0
          maximum: 1
        placeProbability:
          type: number
          description: Predicted place probability (0-1)
          format: float
          minimum: 0
          maximum: 1
        ratingContribution:
          type: number
          description: Contribution from the ratings model to this prediction
          format: float
      required:
        - raceId
        - runnerId
        - winProbability
        - placeProbability

    Tip:
      type: object
      description: A recommended betting tip for a race
      properties:
        id:
          type: string
          description: Unique identifier for the tip
        raceId:
          type: string
          description: ID of the race this tip applies to
        betType:
          type: string
          description: Type of bet recommended
          enum:
            - win
            - place
            - best_bet
            - quinella
            - exacta
            - trifecta
        recommendedBet:
          type: string
          description: Human-readable description of the recommended bet
        confidence:
          type: string
          description: Confidence level of the tip
          enum:
            - low
            - medium
            - high
        reasons:
          type: array
          description: Reasons supporting this tip
          items:
            $ref: "#/components/schemas/TipReason"
        createdAt:
          type: string
          format: date-time
          description: When the tip was generated (ISO 8601)
      required:
        - id
        - raceId
        - betType
        - recommendedBet
        - confidence
        - reasons
        - createdAt

    TipReason:
      type: object
      description: A single reason supporting a tip recommendation
      properties:
        text:
          type: string
          description: Reason text
        type:
          type: string
          description: Sentiment / category of the reason
          enum:
            - positive
            - neutral
            - caution
      required:
        - text
        - type

  # Shared response patterns for reuse
  responses:
    NotFound:
      description: The specified resource was not found
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    BadRequest:
      description: Invalid request parameters
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    InternalError:
      description: Internal server error
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
