openapi: 3.0.3
info:
  title: SissiPark Public API
  description: |
    Public, read-only API for SissiPark apartment resorts.
    Returns apartment details, real-time pricing, and availability.

    **Dual-response:** All endpoints respond with JSON when `Accept: application/json`
    is sent, or HTML otherwise. LLM scrapers and browsers get human-readable HTML;
    AI agents and function-calling tools get structured JSON.
  version: "1.0"
  contact:
    name: SissiPark
    url: https://sissipark.at

servers:
  - url: https://sissipark.at/api/v1
    description: Production
  - url: https://lachtal.sissipark.at/api/v1
    description: Production (Lachtal subdomain — same API)

paths:
  /apartments:
    get:
      operationId: getApartments
      summary: List apartments by location
      description: |
        Returns apartment types with details, amenities, photos, and price ranges.
        When `location` is specified, returns `{location, apartments}`.
        When `location` is omitted, returns `{locations: [{location, apartments}, ...]}` for all locations.
      parameters:
        - name: location
          in: query
          description: "Location slug: lachtal, nassfeld, schladming, tenerife. Omit for all."
          schema:
            type: string
            enum: [lachtal, nassfeld, schladming, tenerife]
        - name: locale
          in: query
          description: "Language for names/descriptions: en, de, hu. Default: en"
          schema:
            type: string
            enum: [en, de, hu]
            default: en
      responses:
        "200":
          description: Apartment list
          content:
            application/json:
              schema:
                type: object
                properties:
                  location:
                    $ref: "#/components/schemas/Location"
                  apartments:
                    type: array
                    items:
                      $ref: "#/components/schemas/Apartment"

  /pricing:
    get:
      operationId: getPricing
      summary: Get real-time pricing for a date range
      description: |
        Returns per-night and total prices for each apartment type.
        Apartment names are always in English. If `partialPricing` is true,
        the date range spans a season gap and prices are incomplete.
      parameters:
        - name: location
          in: query
          required: true
          schema:
            type: string
            enum: [lachtal, nassfeld, schladming, tenerife]
        - name: from
          in: query
          required: true
          description: Check-in date (YYYY-MM-DD)
          schema:
            type: string
            format: date
        - name: to
          in: query
          required: true
          description: Check-out date (YYYY-MM-DD)
          schema:
            type: string
            format: date
      responses:
        "200":
          description: Pricing data
          content:
            application/json:
              schema:
                type: object
                properties:
                  location:
                    type: string
                  period:
                    $ref: "#/components/schemas/Period"
                  currency:
                    type: string
                    example: EUR
                  apartments:
                    type: array
                    items:
                      $ref: "#/components/schemas/PricingItem"
        "422":
          description: Validation error

  /availability:
    get:
      operationId: getAvailability
      summary: Check apartment availability for a date range
      description: |
        Returns available unit counts per apartment type.
        Apartment names are always in English.
      parameters:
        - name: location
          in: query
          required: true
          schema:
            type: string
            enum: [lachtal, nassfeld, schladming, tenerife]
        - name: from
          in: query
          required: true
          schema:
            type: string
            format: date
        - name: to
          in: query
          required: true
          schema:
            type: string
            format: date
      responses:
        "200":
          description: Availability data
          content:
            application/json:
              schema:
                type: object
                properties:
                  location:
                    type: string
                  period:
                    $ref: "#/components/schemas/Period"
                  apartments:
                    type: array
                    items:
                      $ref: "#/components/schemas/AvailabilityItem"
        "422":
          description: Validation error

components:
  schemas:
    Location:
      type: object
      properties:
        name:
          type: string
          example: SissiPark Lachtal
        slug:
          type: string
          example: lachtal
        address:
          type: string
        telephone:
          type: string
        geo:
          type: object
          properties:
            latitude:
              type: number
            longitude:
              type: number
        amenities:
          type: array
          items:
            type: string
        priceRange:
          $ref: "#/components/schemas/PriceRange"

    Apartment:
      type: object
      properties:
        id:
          type: integer
        code:
          type: string
          example: "2A"
        name:
          type: string
        description:
          type: string
        area:
          type: integer
          description: Square meters
        bedrooms:
          type: integer
        bedCount:
          type: integer
        extraBedCount:
          type: integer
        maxGuests:
          type: integer
        amenities:
          type: array
          items:
            type: string
        priceRange:
          $ref: "#/components/schemas/PriceRange"
        thumbnail:
          type: string
          format: uri
          nullable: true
        images:
          type: array
          items:
            type: string
            format: uri
        url:
          type: string
          format: uri
        bookingUrl:
          type: string
          format: uri

    PriceRange:
      type: object
      nullable: true
      properties:
        min:
          type: integer
        max:
          type: integer
        currency:
          type: string
          example: EUR
        unit:
          type: string
          example: night

    Period:
      type: object
      properties:
        from:
          type: string
          format: date
        to:
          type: string
          format: date
        nights:
          type: integer

    PricingItem:
      type: object
      properties:
        id:
          type: integer
        code:
          type: string
        name:
          type: string
        pricePerNight:
          type: integer
        totalPrice:
          type: integer
        pricedNights:
          type: integer
        partialPricing:
          type: boolean
          description: True if date range spans a season gap and prices are incomplete
        season:
          type: string

    AvailabilityItem:
      type: object
      properties:
        id:
          type: integer
        code:
          type: string
        name:
          type: string
        maxGuests:
          type: integer
        totalUnits:
          type: integer
        availableUnits:
          type: integer
        bookingUrl:
          type: string
          format: uri
