openapi: 3.1.0
info:
  title: Eolem Planning API
  description: |
    API REST pour gérer des formations dans Google Calendar.

    Les formations sont créées en tant qu'événements "journée entière" (all-day).
    Le titre est automatiquement formaté `Formation - Client - Lieu`.
    Les horaires sont stockés dans la description de l'événement.

    Google Calendar utilise des dates de fin exclusives : une formation du 15 au 17 avril
    a une date de fin Google au 18 avril. L'API gère cette conversion automatiquement à la création.
  version: 1.0.0
  contact:
    name: Frédéric GAURAT
servers:
  - url: https://planning.eolem.com/api
    description: Production

security:
  - ApiKeyAuth: []

paths:
  /calendar.php:
    get:
      summary: Lister les événements
      description: Retourne les événements dans une plage de dates, ou un événement unique si `id` est fourni.
      operationId: listEvents
      parameters:
        - name: date_start
          in: query
          required: true
          description: Date de début de la plage (format ISO)
          schema:
            type: string
            format: date
          example: "2026-01-01"
        - name: date_end
          in: query
          required: true
          description: Date de fin de la plage (format ISO)
          schema:
            type: string
            format: date
          example: "2026-12-31"
        - name: id
          in: query
          required: false
          description: ID Google Calendar — si fourni, retourne un seul événement au lieu d'une liste
          schema:
            type: string
      responses:
        '200':
          description: Liste d'événements ou événement unique
          content:
            application/json:
              schema:
                oneOf:
                  - type: array
                    items:
                      $ref: '#/components/schemas/Event'
                  - $ref: '#/components/schemas/Event'
              examples:
                liste:
                  summary: Liste de formations
                  value:
                    - id: "abc123def456"
                      summary: "PHP Avancé - Acme Corp - Lyon"
                      location: "Lyon"
                      description: "09:00 - 17:00\nFormation inter-entreprises"
                      colorId: "11"
                      start: "2026-05-04"
                      end: "2026-05-09"
                unique:
                  summary: Événement unique
                  value:
                    id: "abc123def456"
                    summary: "PHP Avancé - Acme Corp - Lyon"
                    location: "Lyon"
                    description: "09:00 - 17:00"
                    colorId: "11"
                    start: "2026-05-04"
                    end: "2026-05-09"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '503':
          $ref: '#/components/responses/GoogleNotAuthenticated'

    post:
      summary: Créer une formation
      description: |
        Crée un événement journée entière dans Google Calendar.
        Le titre est auto-généré au format `Formation - Client - Lieu`.
      operationId: createEvent
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateEventRequest'
            example:
              formation: "PHP Avancé"
              client: "Acme Corp"
              lieu: "Lyon"
              statut: "commandee"
              date_debut: "2026-05-04"
              date_fin: "2026-05-08"
              heure_debut: "09:00"
              heure_fin: "17:00"
              description: "Formation inter-entreprises"
      responses:
        '201':
          description: Formation créée
          content:
            application/json:
              schema:
                type: object
                properties:
                  created:
                    type: array
                    items:
                      $ref: '#/components/schemas/CreatedEvent'
              example:
                created:
                  - id: "abc123def456"
                    summary: "PHP Avancé - Acme Corp - Lyon"
                    start: "2026-05-04"
                    end: "2026-05-09"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/ValidationError'
        '503':
          $ref: '#/components/responses/GoogleNotAuthenticated'

    put:
      summary: Modifier un événement
      description: Mise à jour partielle — seuls les champs fournis sont modifiés.
      operationId: updateEvent
      parameters:
        - name: id
          in: query
          required: true
          description: ID Google Calendar de l'événement à modifier
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateEventRequest'
            examples:
              changerStatut:
                summary: Passer d'option à commandée
                value:
                  statut: "commandee"
              deplacer:
                summary: Changer les dates
                value:
                  date_debut: "2026-05-11"
                  date_fin: "2026-05-15"
      responses:
        '200':
          description: Événement modifié
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Event'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '503':
          $ref: '#/components/responses/GoogleNotAuthenticated'

    delete:
      summary: Supprimer un événement
      operationId: deleteEvent
      parameters:
        - name: id
          in: query
          required: true
          description: ID Google Calendar de l'événement à supprimer
          schema:
            type: string
      responses:
        '204':
          description: Événement supprimé (pas de body)
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '503':
          $ref: '#/components/responses/GoogleNotAuthenticated'

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: Clé API fournie dans le header `X-API-Key` de chaque requête.

  schemas:
    Statut:
      type: string
      enum:
        - option
        - confirmee
        - commandee
      description: |
        - `option` : couleur jaune (Banana, colorId 5)
        - `confirmee` : couleur lavande (Lavender, colorId 1)
        - `commandee` : couleur rouge (Tomato, colorId 11)

    ColorId:
      type: string
      enum:
        - "5"
        - "1"
        - "11"
      description: ID couleur Google Calendar (5=Option, 1=Confirmée, 11=Commandée)

    Event:
      type: object
      required:
        - id
        - summary
        - start
        - end
      properties:
        id:
          type: string
          description: Identifiant Google Calendar de l'événement
          example: "abc123def456"
        summary:
          type: string
          description: Titre au format `Formation - Client - Lieu`
          example: "PHP Avancé - Acme Corp - Lyon"
        location:
          type: string
          description: Lieu de la formation
          example: "Lyon"
        description:
          type: string
          description: |
            Première ligne = horaires au format `HH:MM - HH:MM`.
            Lignes suivantes = notes libres.
          example: "09:00 - 17:00\nFormation inter-entreprises"
        colorId:
          $ref: '#/components/schemas/ColorId'
        start:
          type: string
          format: date
          description: Date de début (inclusive)
          example: "2026-05-04"
        end:
          type: string
          format: date
          description: Date de fin exclusive (dernier jour + 1, convention Google Calendar)
          example: "2026-05-09"

    CreatedEvent:
      type: object
      required:
        - id
        - summary
        - start
        - end
      properties:
        id:
          type: string
          example: "abc123def456"
        summary:
          type: string
          example: "PHP Avancé - Acme Corp - Lyon"
        start:
          type: string
          format: date
          example: "2026-05-04"
        end:
          type: string
          format: date
          description: Date exclusive (dernier jour + 1)
          example: "2026-05-09"

    CreateEventRequest:
      type: object
      required:
        - formation
        - client
        - lieu
        - statut
        - date_debut
        - date_fin
      properties:
        formation:
          type: string
          description: Nom de la formation
          minLength: 1
          example: "PHP Avancé"
        client:
          type: string
          description: Nom du client
          minLength: 1
          example: "Acme Corp"
        lieu:
          type: string
          description: Lieu de la formation
          minLength: 1
          example: "Lyon"
        statut:
          $ref: '#/components/schemas/Statut'
        date_debut:
          type: string
          format: date
          description: Premier jour de la formation (inclusive)
          example: "2026-05-04"
        date_fin:
          type: string
          format: date
          description: Dernier jour de la formation (inclusive, doit être >= date_debut)
          example: "2026-05-08"
        heure_debut:
          type: string
          pattern: '^\d{2}:\d{2}$'
          default: "09:00"
          description: Heure de début au format HH:MM
          example: "09:00"
        heure_fin:
          type: string
          pattern: '^\d{2}:\d{2}$'
          default: "17:00"
          description: Heure de fin au format HH:MM (doit être > heure_debut)
          example: "17:00"
        description:
          type: string
          default: ""
          description: Notes libres ajoutées à la description de l'événement
          example: "Formation inter-entreprises"

    UpdateEventRequest:
      type: object
      description: Tous les champs sont optionnels — seuls les champs fournis sont modifiés.
      properties:
        summary:
          type: string
          description: Nouveau titre complet
          example: "Angular Avancé - Orsys - Lyon"
        location:
          type: string
          description: Nouveau lieu
          example: "Paris"
        description:
          type: string
          description: Nouvelle description
        statut:
          $ref: '#/components/schemas/Statut'
        colorId:
          $ref: '#/components/schemas/ColorId'
        date_debut:
          type: string
          format: date
          description: Nouvelle date de début
          example: "2026-05-11"
        date_fin:
          type: string
          format: date
          description: Nouvelle date de fin (inclusive, convertie en exclusive automatiquement)
          example: "2026-05-15"

    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: Message d'erreur lisible
        details:
          description: Détails supplémentaires (format variable selon l'erreur)
          oneOf:
            - type: string
            - type: object

    ValidationErrorDetails:
      type: object
      description: Map des erreurs par champ
      additionalProperties:
        type: string
      example:
        formation: "La formation est obligatoire."
        date_fin: "La date de fin doit être égale ou postérieure à la date de début."

  responses:
    BadRequest:
      description: Paramètres manquants ou body JSON invalide
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: "Paramètres date_start et date_end requis"

    Unauthorized:
      description: API key invalide ou manquante
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: "API key invalide ou manquante"

    ValidationError:
      description: Échec de la validation du body
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
              details:
                $ref: '#/components/schemas/ValidationErrorDetails'
          example:
            error: "Validation échouée"
            details:
              formation: "La formation est obligatoire."
              statut: "Le statut est invalide."

    GoogleNotAuthenticated:
      description: Google Calendar non authentifié côté serveur (passer par l'interface web une première fois pour faire le flux OAuth)
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: "Google Calendar non authentifié. Connectez-vous via l'interface web d'abord."
