openapi: 3.0.3
info:
  title: PUP - Player API v1
  description: >
    PUP is the universal player profile for padel. Players can use PUP to track their performance, playing style, and 
    statistics – no matter where they play.
  version: 1.0.0

servers:
  - url: https://api.gopup.app/
    description: Development server

x-tagGroups:
  - name: Player
    tags:
      - player

tags:
  - name: player
    x-displayName: "Player"
    description: Operations related to players

paths:
  /player/v1/search:
    get:
      tags:
        - player
      summary: Search players
      description: Returns paginated list of results
      operationId: searchPlayers
      parameters:
        - in: query
          name: term
          example: John
          schema:
            type: string
        - in: query
          name: club
          example: Home padel
          schema:
            type: string
        - in: query
          name: best_hand
          example: both
          description: >
            One of: left, right, both
          schema:
            type: string
            enum: ["left", "right", "both"]
        - in: query
          name: position_on_court
          example: left
          description: >
            One of: left, right, both
          schema:
            type: string
            enum: ["left", "right", "both"]
        - in: query
          name: offset
          example: 20
          description: Results offset (useful for pagination)
          schema:
            type: integer
        - in: query
          name: limit
          example: 20
          description: Results limit (useful for pagination)
          schema:
            type: integer
      security:
        - OAuth2:
            - urn:pup:player:read
        - PAT: []
      responses:
        '200':
          description: The search results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchResponse'
        '401':
          description: Unauthorized - invalid or missing JWT
          content:
            application/json:
              schema:
                type: object
                required:
                  - error
                properties:
                  error:
                    type: string
                    example: "invalid or missing token"
        default:
          description: Generic error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

  /player/v1/player/{id}:
    get:
      tags:
        - player
      parameters:
        - in: path
          name: id
          description: Player identifier
          example: 155eb3b5-30f8-4ff5-ae74-4f9570c28ebe
          required: true
          schema:
            type: string
      summary: Show the profile of a player by ID
      description: Returns the profile details of a player
      operationId: getPlayer
      security:
        - OAuth2:
            - urn:pup:player:read
        - PAT: []
      responses:
        '200':
          description: The requested player profile details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PlayerResponse'
        '404':
          description: Player not found
          content:
            application/json:
              schema:
                type: object
                required:
                  - error
                properties:
                  error:
                    type: string
                    example: "Player not found"
        '401':
          description: Unauthorized - invalid or missing JWT
          content:
            application/json:
              schema:
                type: object
                required:
                  - error
                properties:
                  error:
                    type: string
                    example: "invalid or missing token"
        default:
          description: Generic error
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"

components:
  schemas:
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          example: "An error message"
      description: Generic error response

    Player:
      type: object
      required:
        - id
        - first_name
        - last_name
        - pup_score
      properties:
        id:
          type: string
          description: Player identifier
          example: 155eb3b5-30f8-4ff5-ae74-4f9570c28ebe
        first_name:
          type: string
          description: Player’s first name
          example: "Alice"
        last_name:
          type: string
          description: Player’s last name
          example: "Johnson"
        country_code:
          type: string
          nullable: true
          description: Country code (ISO 3166-1 alpha-2 code)
          enum: [ AF, AX, AL, DZ, AS, AD, AO, AI, AQ, AG, AR, AM, AW, AU, AT, AZ, BS, BH, BD, BB, BY, BE, BZ, BJ, BM, BT, BO, BQ, BA, BW, BV, BR, IO, BN, BG, BF, BI, CV, KH, CM, CA, KY, CF, TD, CL, CN, CX, CC, CO, KM, CG, CD, CK, CR, CI, HR, CU, CW, CY, CZ, DK, DJ, DM, DO, EC, EG, SV, GQ, ER, EE, SZ, ET, FK, FO, FJ, FI, FR, GF, PF, TF, GA, GM, GE, DE, GH, GI, GR, GL, GD, GP, GU, GT, GG, GN, GW, GY, HT, HM, VA, HN, HK, HU, IS, IN, ID, IR, IQ, IE, IM, IL, IT, JM, JP, JE, JO, KZ, KE, KI, KP, KR, KW, KG, LA, LV, LB, LS, LR, LY, LI, LT, LU, MO, MG, MW, MY, MV, ML, MT, MH, MQ, MR, MU, YT, MX, FM, MD, MC, MN, ME, MS, MA, MZ, MM, NA, NR, NP, NL, NC, NZ, NI, NE, NG, NU, NF, MK, MP, "NO", OM, PK, PW, PS, PA, PG, PY, PE, PH, PN, PL, PT, PR, QA, RE, RO, RU, RW, BL, SH, KN, LC, MF, PM, VC, WS, SM, ST, SA, SN, RS, SC, SL, SG, SX, SK, SI, SB, SO, ZA, GS, SS, ES, LK, SD, SR, SJ, SE, CH, SY, TW, TJ, TZ, TH, TL, TG, TK, TO, TT, TN, TR, TM, TC, TV, UG, UA, AE, GB, US, UM, UY, UZ, VU, VE, VN, VG, VI, WF, EH, YE, ZM, ZW ]
        bio:
          type: string
          nullable: true
          description: Short biography of the player
          example: "Passionate padel player with 2 years of experience"
        club:
          type: string
          nullable: true
          description: The player's club
          example: "Home padel"
        knltb_profile_url:
          type: string
          format: uri
          description: URL to the official KNLTB profile
          example: "https://mijnknltb.toernooi.nl/player-profile/e52a3bc3-9ccc-4ed1-be66-de7510a61f86"
        best_hand:
          type: string
          enum: ["left", "right", "both"]
        position_on_court:
          type: string
          enum: ["left", "right", "both"]
        picture_url:
          type: string
          format: uri
          description: "URL to profile picture"
          example: "https://cdn.example.com/profile/b6d563ab-d1bf-493f-bde2-2d9474c6e596.png"
        skills:
          type: object
          properties:
            points:
              type: object
              properties:
                allocated:
                  $ref: "#/components/schemas/Skills"
        ratings:
          type: array
          items:
            $ref: "#/components/schemas/Rating"
        pup_score:
          type: integer
          minimum: 0
          example: 67
          description: "The PUP score is based on unified overall rating from all sources (providers such as KNLTB, Playtomic)"
        age:
          type: integer
          nullable: true
          minimum: 0
          example: 26
          description: "Age in years calculated from date of birth"

    Skill:
      type: integer
      example: 67
      minimum: 0
      maximum: 99
      description: Points allocated to a skill

    Skills:
      type: object
      additionalProperties: false
      required:
        - physical
        - forehand
        - back
        - volley
        - bajada
        - vibora
        - bandeja
        - smash
        - defense
      properties:
        physical:
          $ref: "#/components/schemas/Skill"
        forehand:
          $ref: "#/components/schemas/Skill"
        back:
          $ref: "#/components/schemas/Skill"
        volley:
          $ref: "#/components/schemas/Skill"
        bajada:
          $ref: "#/components/schemas/Skill"
        vibora:
          $ref: "#/components/schemas/Skill"
        bandeja:
          $ref: "#/components/schemas/Skill"
        smash:
          $ref: "#/components/schemas/Skill"
        defense:
          $ref: "#/components/schemas/Skill"

    Rating:
      type: object
      required:
        - provider
        - rating
      properties:
        provider:
          type: string
          example: "KNLTB"
          description: "Name of the rating provider"
        rating:
          type: string
          example: "5.12345"
          pattern: '^\d+(\.\d+)?$'

    ResponseMetaMany:
      type: object
      required:
        - pagination
      properties:
        pagination:
          type: object
          required:
            - total
            - returned
            - offset
            - limit
          properties:
            total:
              type: integer
              description: Total number of matching records
              example: 145
            returned:
              type: integer
              description: Number of records actually returned in this response
              example: 20
            offset:
              type: integer
              description: Offset used in the request
              example: 100
            limit:
              type: integer
              description: Limit used in the request
              example: 20
            next:
              type: string
              description: Relative path to next page of results
              example: /player/v1/search?term=something&offset=120&limit=20
            previous:
              type: string
              description: Relative path to previous page of results
              example: /player/v1/search?term=something&offset=80&limit=20

    PlayerResponse:
      type: object
      properties:
        player:
          $ref: '#/components/schemas/Player'

    SearchResponse:
      type: object
      required:
        - hits
        - meta
      properties:
        hits:
          type: array
          items:
            $ref: '#/components/schemas/Player'
        meta:
          $ref: '#/components/schemas/ResponseMetaMany'

  securitySchemes:
    OAuth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: "https://oauth2.gopup.app/oauth2/auth"
          tokenUrl: "https://oauth2.gopup.app/oauth2/token"
          scopes:
            urn:pup:player:read: "Read player data"
      description: OAuth2

    PAT:
      type: http
      scheme: bearer
      bearerFormat: PAT
      description: Personal Access Token
