# language: fr

Fonctionnalité: API - Progression et synchronisation audio-guides
  En tant que système backend
  Je veux sauvegarder et synchroniser la progression des audio-guides
  Afin de permettre une reprise fluide et multi-device

  Contexte:
    Étant donné que l'API RoadWave est démarrée
    Et que l'utilisateur "user@example.com" est authentifié

  # 16.6.1 - Sauvegarde progression

  Scénario: POST /api/v1/audio-guides/{id}/progress - Sauvegarde progression
    Étant donné un audio-guide "ag_123" en cours d'écoute
    Et que l'utilisateur est à la séquence 3 position 1:42
    Quand je fais un POST sur "/api/v1/audio-guides/ag_123/progress":
      """json
      {
        "current_sequence_id": "seq_3",
        "current_position_seconds": 102,
        "completed_sequences": ["seq_1", "seq_2"],
        "gps_position": {
          "latitude": 43.1234,
          "longitude": 2.5678
        }
      }
      """
    Alors le code HTTP de réponse est 200
    Et la progression est sauvegardée en PostgreSQL
    Et le timestamp last_played_at est mis à jour
    Et le corps de réponse contient:
      """json
      {
        "saved": true,
        "synced_to_cloud": true,
        "updated_at": "2026-01-22T14:35:42Z"
      }
      """

  Scénario: Sauvegarde automatique toutes les 30 secondes (client)
    Étant donné que le client mobile envoie la progression toutes les 30s
    Quand je fais un POST sur "/api/v1/audio-guides/{id}/progress"
    Alors la progression précédente est écrasée
    Et le timestamp est mis à jour
    Et la réponse est retournée en < 100ms

  Scénario: Sauvegarde des séquences complétées (>80%)
    Étant donné qu'une séquence de durée 180 secondes
    Et que l'utilisateur a écouté 150 secondes (83%)
    Quand la progression est sauvegardée
    Alors la séquence est ajoutée à completed_sequences
    Et le completion_rate est enregistré à 83%

  Scénario: Séquence non marquée complétée si <80%
    Étant donné qu'une séquence de durée 222 secondes
    Et que l'utilisateur a écouté 90 secondes (40%)
    Quand la progression est sauvegardée
    Alors la séquence n'est PAS ajoutée à completed_sequences
    Et le current_position est sauvegardé (pour reprise)

  Scénario: Structure de données progression en PostgreSQL
    Étant donné une sauvegarde de progression
    Alors la table audio_guide_progress contient:
      | champ                 | type        | description                          |
      | id                    | UUID        | ID progression                       |
      | user_id               | UUID        | ID utilisateur                       |
      | audio_guide_id        | UUID        | ID audio-guide                       |
      | current_sequence_id   | UUID        | Séquence en cours                    |
      | current_position      | INTEGER     | Position en secondes                 |
      | completed_sequences   | UUID[]      | Tableau séquences complétées         |
      | last_played_at        | TIMESTAMP   | Dernière écoute                      |
      | gps_position          | GEOGRAPHY   | Position GPS optionnelle             |
      | created_at            | TIMESTAMP   | Création                             |
      | updated_at            | TIMESTAMP   | Dernière MAJ                         |

  # 16.6.2 - Reprise progression

  Scénario: GET /api/v1/audio-guides/{id}/progress - Récupération progression
    Étant donné une progression sauvegardée pour "ag_123"
    Quand je fais un GET sur "/api/v1/audio-guides/ag_123/progress"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient:
      """json
      {
        "has_progress": true,
        "current_sequence_id": "seq_3",
        "current_position_seconds": 102,
        "completed_sequences": ["seq_1", "seq_2"],
        "completion_percentage": 25,
        "last_played_at": "2026-01-20T14:35:42Z",
        "can_resume": true
      }
      """

  Scénario: Calcul completion_percentage
    Étant donné un audio-guide de 12 séquences
    Et que l'utilisateur a complété 3 séquences
    Quand le pourcentage de complétion est calculé
    Alors completion_percentage est 25% (3/12)

  Scénario: Progression inexistante (première écoute)
    Étant donné qu'aucune progression n'existe pour "ag_456"
    Quand je fais un GET sur "/api/v1/audio-guides/ag_456/progress"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient:
      """json
      {
        "has_progress": false,
        "can_resume": false
      }
      """

  Scénario: Progression expirée (>30 jours)
    Étant donné une progression avec last_played_at à 35 jours
    Quand je fais un GET sur "/api/v1/audio-guides/ag_123/progress"
    Alors can_resume est false
    Et le message "Progression expirée après 30 jours" est retourné
    Et les données sont conservées mais marquées "expired"

  Scénario: DELETE /api/v1/audio-guides/{id}/progress - Réinitialisation
    Étant donné une progression existante
    Quand je fais un DELETE sur "/api/v1/audio-guides/ag_123/progress"
    Alors le code HTTP de réponse est 204
    Et la progression est supprimée
    Et l'utilisateur peut recommencer depuis le début

  # 16.6.3 - Multi-device et synchronisation

  Scénario: Synchronisation cloud automatique
    Étant donné qu'une progression est sauvegardée sur iPhone
    Quand l'utilisateur ouvre l'app sur iPad
    Et fait un GET sur "/api/v1/audio-guides/ag_123/progress"
    Alors la progression iPhone est récupérée
    Et l'utilisateur peut reprendre exactement où il était

  Scénario: Conflit de synchronisation (dernier timestamp gagne)
    Étant donné une progression sur iPhone avec timestamp "2026-01-22T14:00:00Z"
    Et une progression sur iPad avec timestamp "2026-01-22T14:05:00Z"
    Quand les deux appareils synchronisent
    Alors la progression avec timestamp le plus récent (iPad) est conservée
    Et la progression iPhone est écrasée

  Scénario: GET /api/v1/audio-guides/progress/sync - Synchronisation batch
    Étant donné que l'utilisateur a 5 progressions locales non synchronisées
    Quand je fais un POST sur "/api/v1/audio-guides/progress/sync":
      """json
      {
        "progressions": [
          {
            "audio_guide_id": "ag_1",
            "current_sequence_id": "seq_3",
            "current_position_seconds": 102,
            "updated_at": "2026-01-22T14:00:00Z"
          },
          {
            "audio_guide_id": "ag_2",
            "current_sequence_id": "seq_5",
            "current_position_seconds": 45,
            "updated_at": "2026-01-22T14:10:00Z"
          }
        ]
      }
      """
    Alors le code HTTP de réponse est 200
    Et toutes les progressions sont synchronisées
    Et le corps de réponse contient:
      """json
      {
        "synced_count": 2,
        "conflicts": 0
      }
      """

  Scénario: Résolution conflit avec notification
    Étant donné une progression locale sur iPhone avec timestamp ancien
    Et une progression cloud plus récente (depuis iPad)
    Quand le sync est effectué
    Alors la progression cloud est conservée
    Et un conflit est signalé dans la réponse:
      """json
      {
        "synced_count": 1,
        "conflicts": 1,
        "conflict_details": [
          {
            "audio_guide_id": "ag_123",
            "cloud_timestamp": "2026-01-22T15:00:00Z",
            "local_timestamp": "2026-01-22T14:30:00Z",
            "resolution": "cloud_wins"
          }
        ]
      }
      """

  # Historique et statistiques

  Scénario: GET /api/v1/audio-guides/progress/history - Historique écoutes
    Étant donné que l'utilisateur a écouté 3 séquences d'un audio-guide
    Quand je fais un GET sur "/api/v1/audio-guides/ag_123/progress/history"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient l'historique:
      """json
      {
        "listening_sessions": [
          {
            "sequence_id": "seq_1",
            "started_at": "2026-01-22T14:10:00Z",
            "completed_at": "2026-01-22T14:12:15Z",
            "completion_rate": 100,
            "duration_listened": 135
          },
          {
            "sequence_id": "seq_2",
            "started_at": "2026-01-22T14:12:20Z",
            "completed_at": "2026-01-22T14:14:08Z",
            "completion_rate": 100,
            "duration_listened": 108
          },
          {
            "sequence_id": "seq_3",
            "started_at": "2026-01-22T14:14:15Z",
            "completed_at": "2026-01-22T14:17:45Z",
            "completion_rate": 92,
            "duration_listened": 204
          }
        ],
        "total_time_spent": 447
      }
      """

  Scénario: Détection complétion 100% de l'audio-guide
    Étant donné un audio-guide de 12 séquences
    Et que l'utilisateur complète la 12ème et dernière séquence à >80%
    Quand la progression est sauvegardée
    Alors is_completed passe à true
    Et completed_at est mis à jour avec le timestamp actuel
    Et un événement "audio_guide_completed" est émis

  Scénario: GET /api/v1/users/me/audio-guides/completed - Liste des complétés
    Étant donné que l'utilisateur a complété 2 audio-guides
    Quand je fais un GET sur "/api/v1/users/me/audio-guides/completed"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient:
      """json
      {
        "completed_count": 2,
        "audio_guides": [
          {
            "audio_guide_id": "ag_1",
            "title": "Tour de Paris",
            "completed_at": "2026-01-15T10:00:00Z",
            "total_sequences": 10,
            "total_duration": 3600
          },
          {
            "audio_guide_id": "ag_2",
            "title": "Découverte de Lyon",
            "completed_at": "2026-01-20T14:00:00Z",
            "total_sequences": 8,
            "total_duration": 2700
          }
        ]
      }
      """

  Scénario: GET /api/v1/users/me/audio-guides/in-progress - Liste en cours
    Étant donné que l'utilisateur a 3 audio-guides en cours
    Quand je fais un GET sur "/api/v1/users/me/audio-guides/in-progress"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient:
      """json
      {
        "in_progress_count": 3,
        "audio_guides": [
          {
            "audio_guide_id": "ag_123",
            "title": "Visite du Louvre",
            "current_sequence": 6,
            "total_sequences": 12,
            "completion_percentage": 50,
            "last_played_at": "2026-01-22T14:35:42Z"
          }
        ]
      }
      """

  # Badges et achievements

  Scénario: Attribution badge "Premier audio-guide"
    Étant donné qu'un utilisateur complète son 1er audio-guide
    Quand le système détecte la complétion
    Alors un badge "first_audio_guide" est attribué
    Et une notification est envoyée:
      """json
      {
        "type": "badge_unlocked",
        "badge_id": "first_audio_guide",
        "title": "🎧 Premier audio-guide",
        "message": "Félicitations ! Vous avez complété votre premier audio-guide"
      }
      """

  Plan du Scénario: Attribution badges selon nombre complétés
    Étant donné qu'un utilisateur complète son <nombre>ème audio-guide
    Quand le système détecte la complétion
    Alors le badge "<badge_id>" est attribué

    Exemples:
      | nombre | badge_id           |
      | 1      | first_audio_guide  |
      | 5      | explorer           |
      | 10     | completist         |
      | 25     | expert             |
      | 50     | master             |

  # Nettoyage et archivage

  Scénario: Archivage progressions inactives (>6 mois)
    Étant donné une progression avec last_played_at à 200 jours
    Quand le job de nettoyage automatique s'exécute
    Alors la progression est déplacée vers la table audio_guide_progress_archive
    Et elle reste récupérable via l'API pendant 30 jours supplémentaires
    Et après 7 mois total, elle est supprimée définitivement

  Scénario: GET /api/v1/audio-guides/{id}/progress/archived - Récupération archivée
    Étant donné une progression archivée
    Quand je fais un GET sur "/api/v1/audio-guides/ag_123/progress/archived"
    Alors le code HTTP de réponse est 200
    Et la progression archivée est retournée
    Et un message indique: "Progression archivée. Vous pouvez la restaurer."

  Scénario: POST /api/v1/audio-guides/{id}/progress/restore - Restauration
    Étant donné une progression archivée
    Quand je fais un POST sur "/api/v1/audio-guides/ag_123/progress/restore"
    Alors le code HTTP de réponse est 200
    Et la progression est déplacée de archive vers la table active
    Et l'utilisateur peut reprendre son écoute

  # Cas d'erreur

  Scénario: Sauvegarde progression audio-guide inexistant
    Quand je fais un POST sur "/api/v1/audio-guides/ag_nonexistant/progress"
    Alors le code HTTP de réponse est 404
    Et le message d'erreur est "Audio-guide non trouvé"

  Scénario: Sauvegarde progression séquence invalide
    Étant donné un audio-guide "ag_123" avec 8 séquences
    Et une requête avec current_sequence_id "seq_99" (inexistant)
    Quand je fais un POST sur "/api/v1/audio-guides/ag_123/progress"
    Alors le code HTTP de réponse est 400
    Et le message d'erreur est "Séquence inexistante pour cet audio-guide"

  Scénario: Récupération progression sans authentification
    Étant donné une requête sans token JWT
    Quand je fais un GET sur "/api/v1/audio-guides/ag_123/progress"
    Alors le code HTTP de réponse est 401
    Et le message d'erreur est "Authentification requise"

  Scénario: Corruption de données progression (récupération)
    Étant donné une progression avec données corrompues (JSON invalide)
    Quand je fais un GET sur "/api/v1/audio-guides/ag_123/progress"
    Alors le système tente une récupération depuis le backup quotidien
    Et si récupération réussie, les données sont restaurées
    Et un log d'erreur est créé pour investigation

  Scénario: Échec synchronisation cloud (mode dégradé)
    Étant donné que la base PostgreSQL est temporairement indisponible
    Quand je fais un POST sur "/api/v1/audio-guides/ag_123/progress"
    Alors le code HTTP de réponse est 503
    Et le message d'erreur est "Service temporairement indisponible. Réessayez dans quelques instants."
    Et le client doit conserver la progression localement et réessayer

  # Performance et optimisations

  Scénario: Index sur user_id + audio_guide_id pour requêtes rapides
    Étant donné un index composite (user_id, audio_guide_id)
    Quand je fais un GET sur "/api/v1/audio-guides/ag_123/progress"
    Alors la requête PostgreSQL utilise l'index
    Et le temps de réponse est < 20ms

  Scénario: Cache Redis pour progressions actives
    Étant donné qu'une progression est fréquemment mise à jour (toutes les 30s)
    Quand la progression est sauvegardée
    Alors elle est également cachée dans Redis avec TTL 1h
    Et les GET suivants lisent depuis Redis (pas PostgreSQL)
    Et la latence est < 10ms

  Scénario: Invalidation cache Redis lors de réinitialisation
    Étant donné qu'une progression est en cache Redis
    Quand je fais un DELETE sur "/api/v1/audio-guides/ag_123/progress"
    Alors l'entrée cache Redis est supprimée
    Et la base PostgreSQL est mise à jour
    Et la cohérence est garantie
