# language: fr

Fonctionnalité: API - Métriques et analytics audio-guides
  En tant que système backend
  Je veux collecter et exposer les métriques d'écoute des audio-guides
  Afin de fournir des insights aux créateurs

  Contexte:
    Étant donné que l'API RoadWave est démarrée
    Et que le créateur "creator@example.com" est authentifié

  # Statistiques globales audio-guide

  Scénario: GET /api/v1/creators/me/audio-guides/{id}/stats - Statistiques générales
    Étant donné un audio-guide "ag_123" avec les métriques suivantes:
      | ecoutes_totales | ecoutes_completes | taux_completion | temps_ecoute_total |
      | 1542            | 892               | 58%             | 423h               |
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/stats"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient:
      """json
      {
        "listens_total": 1542,
        "listens_complete": 892,
        "completion_rate": 58,
        "total_listen_time_seconds": 1522800,
        "avg_listen_time_seconds": 988,
        "unique_listeners": 1124,
        "repeat_listeners": 418
      }
      """

  Scénario: Statistiques par période (7j, 30j, 90j, all-time)
    Étant donné un audio-guide avec historique
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/stats?period=7d"
    Alors le code HTTP de réponse est 200
    Et les statistiques sur les 7 derniers jours sont retournées

  Plan du Scénario: Périodes disponibles
    Quand je fais un GET avec period=<period>
    Alors les stats de la période <description> sont retournées

    Exemples:
      | period  | description         |
      | 7d      | 7 derniers jours    |
      | 30d     | 30 derniers jours   |
      | 90d     | 90 derniers jours   |
      | all     | Depuis la création  |

  # Métriques par séquence

  Scénario: GET /api/v1/creators/me/audio-guides/{id}/sequences/stats - Stats par séquence
    Étant donné un audio-guide de 12 séquences
    Et les métriques suivantes:
      | sequence | starts | completions | abandon_rate |
      | 1        | 1000   | 950         | 5%           |
      | 2        | 950    | 920         | 3%           |
      | 3        | 920    | 850         | 8%           |
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/sequences/stats"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient:
      """json
      {
        "sequences": [
          {
            "sequence_id": "seq_1",
            "sequence_number": 1,
            "title": "Introduction",
            "starts": 1000,
            "completions": 950,
            "completion_rate": 95,
            "abandon_rate": 5,
            "avg_listen_time": 132,
            "duration": 135
          },
          {
            "sequence_id": "seq_2",
            "sequence_number": 2,
            "title": "Pyramide du Louvre",
            "starts": 950,
            "completions": 920,
            "completion_rate": 97,
            "abandon_rate": 3,
            "avg_listen_time": 106,
            "duration": 108
          }
        ]
      }
      """

  Scénario: Identification séquence la plus écoutée
    Étant donné les statistiques par séquence
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/sequences/top"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient:
      """json
      {
        "most_listened": {
          "sequence_id": "seq_3",
          "title": "La Joconde",
          "starts": 920,
          "reason": "popular_highlight"
        },
        "least_listened": {
          "sequence_id": "seq_11",
          "title": "Aile Richelieu",
          "starts": 580,
          "reason": "late_sequence"
        }
      }
      """

  # Points d'abandon

  Scénario: Détection point d'abandon critique
    Étant donné un audio-guide avec taux de complétion 58%
    Et que 35% des utilisateurs abandonnent à la séquence 7
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/abandon-analysis"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient:
      """json
      {
        "critical_abandon_point": {
          "sequence_id": "seq_7",
          "sequence_number": 7,
          "title": "Aile Richelieu",
          "abandon_rate": 35,
          "severity": "high",
          "suggestion": "Réduire la durée (8 min actuellement) ou rendre plus captivant"
        }
      }
      """

  Scénario: Heatmap des abandons
    Étant donné un audio-guide
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/abandon-heatmap"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient une heatmap:
      """json
      {
        "heatmap": [
          {"sequence": 1, "abandon_count": 50, "intensity": "low"},
          {"sequence": 2, "abandon_count": 30, "intensity": "low"},
          {"sequence": 7, "abandon_count": 320, "intensity": "high"},
          {"sequence": 12, "abandon_count": 70, "intensity": "medium"}
        ]
      }
      """

  # Métriques géographiques

  Scénario: GET /api/v1/creators/me/audio-guides/{id}/geographic-stats - Stats géo
    Étant donné un audio-guide géolocalisé
    Et les écoutes suivantes par région:
      | region        | listens | completions |
      | Île-de-France | 850     | 520         |
      | PACA          | 320     | 180         |
      | Auvergne      | 145     | 90          |
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/geographic-stats"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient:
      """json
      {
        "by_region": [
          {
            "region": "Île-de-France",
            "listens": 850,
            "completions": 520,
            "completion_rate": 61
          },
          {
            "region": "PACA",
            "listens": 320,
            "completions": 180,
            "completion_rate": 56
          }
        ]
      }
      """

  Scénario: Heatmap géographique des écoutes
    Étant donné un audio-guide avec points GPS
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/geographic-heatmap"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient:
      """json
      {
        "points": [
          {
            "sequence_id": "seq_1",
            "gps_point": {"lat": 43.1234, "lon": 2.5678},
            "listen_count": 1000,
            "density": "high"
          },
          {
            "sequence_id": "seq_2",
            "gps_point": {"lat": 43.1245, "lon": 2.5690},
            "listen_count": 950,
            "density": "high"
          }
        ]
      }
      """

  # Métriques déclenchement GPS

  Scénario: Attribution GPS auto vs manuel
    Étant donné un audio-guide voiture avec 8 points GPS
    Et les déclenchements suivants:
      | type           | count |
      | GPS auto       | 542   |
      | Manuel         | 123   |
      | Point manqué   | 89    |
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/trigger-stats"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient:
      """json
      {
        "total_triggers": 754,
        "by_type": {
          "gps_auto": 542,
          "manual": 123,
          "missed_point": 89
        },
        "gps_auto_rate": 72,
        "manual_rate": 16,
        "missed_rate": 12
      }
      """

  Scénario: Points GPS les plus manqués
    Étant donné les statistiques de points manqués
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/missed-points"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient:
      """json
      {
        "most_missed": [
          {
            "sequence_id": "seq_5",
            "title": "Enclos des éléphants",
            "missed_count": 45,
            "missed_rate": 12,
            "suggestion": "Rayon trop petit (30m) ou point mal placé"
          }
        ]
      }
      """

  # Temps moyen par séquence

  Scénario: Comparaison durée audio vs temps d'écoute moyen
    Étant donné les métriques temporelles suivantes:
      | sequence | duration | avg_listen_time | ecart  |
      | 1        | 135      | 130             | -5s    |
      | 2        | 108      | 90              | -18s   |
      | 3        | 222      | 220             | -2s    |
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/time-analysis"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient:
      """json
      {
        "sequences": [
          {
            "sequence_id": "seq_1",
            "duration_seconds": 135,
            "avg_listen_time": 130,
            "delta": -5,
            "completion_avg": 96
          },
          {
            "sequence_id": "seq_2",
            "duration_seconds": 108,
            "avg_listen_time": 90,
            "delta": -18,
            "completion_avg": 83,
            "warning": "Séquence souvent skippée ou abandonnée avant la fin"
          }
        ]
      }
      """

  # Notifications milestones

  Scénario: POST /api/v1/audio-guides/{id}/milestones/check - Vérification milestone
    Étant donné qu'un audio-guide atteint 1000 écoutes
    Quand le système vérifie les milestones
    Alors un événement "milestone_reached" est émis
    Et une notification est envoyée au créateur:
      """json
      {
        "type": "milestone",
        "milestone_type": "listens_1000",
        "audio_guide_id": "ag_123",
        "message": "Félicitations ! Votre audio-guide 'Visite du Louvre' a atteint 1000 écoutes !",
        "stats": {
          "listens": 1000,
          "completion_rate": 58
        }
      }
      """

  Plan du Scénario: Milestones prédéfinis
    Étant donné qu'un audio-guide atteint <seuil> écoutes
    Quand le milestone est vérifié
    Alors une notification "<type>" est envoyée

    Exemples:
      | seuil | type          |
      | 100   | listens_100   |
      | 500   | listens_500   |
      | 1000  | listens_1000  |
      | 5000  | listens_5000  |
      | 10000 | listens_10000 |

  # Graphiques et visualisations

  Scénario: GET /api/v1/creators/me/audio-guides/{id}/completion-funnel - Entonnoir complétion
    Étant donné un audio-guide de 12 séquences
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/completion-funnel"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient un graphique en entonnoir:
      """json
      {
        "funnel": [
          {"sequence": 1, "listeners": 1000, "percentage": 100},
          {"sequence": 2, "listeners": 950, "percentage": 95},
          {"sequence": 3, "listeners": 890, "percentage": 89},
          {"sequence": 12, "listeners": 580, "percentage": 58}
        ]
      }
      """

  Scénario: GET /api/v1/creators/me/audio-guides/{id}/listens-over-time - Écoutes dans le temps
    Étant donné un audio-guide avec historique
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/listens-over-time?period=30d"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient une série temporelle:
      """json
      {
        "period": "30d",
        "granularity": "day",
        "data_points": [
          {"date": "2026-01-01", "listens": 45, "completions": 28},
          {"date": "2026-01-02", "listens": 52, "completions": 31},
          {"date": "2026-01-03", "listens": 38, "completions": 24}
        ]
      }
      """

  # Comparaisons et benchmarks

  Scénario: GET /api/v1/creators/me/audio-guides/compare - Comparaison audio-guides
    Étant donné que le créateur a 3 audio-guides:
      | audio_guide_id | title            | listens | completion_rate |
      | ag_1           | Tour de Paris    | 1200    | 65%             |
      | ag_2           | Visite Louvre    | 1542    | 58%             |
      | ag_3           | Safari du Paugre | 890     | 72%             |
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/compare"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient:
      """json
      {
        "audio_guides": [
          {
            "audio_guide_id": "ag_2",
            "title": "Visite Louvre",
            "listens": 1542,
            "completion_rate": 58,
            "rank_by_listens": 1,
            "rank_by_completion": 2
          },
          {
            "audio_guide_id": "ag_1",
            "title": "Tour de Paris",
            "listens": 1200,
            "completion_rate": 65,
            "rank_by_listens": 2,
            "rank_by_completion": 1
          }
        ]
      }
      """

  Scénario: Benchmark par rapport à la moyenne plateforme
    Étant donné qu'un audio-guide a un taux de complétion de 58%
    Et que la moyenne plateforme pour la catégorie "musée" est 62%
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/benchmark"
    Alors le code HTTP de réponse est 200
    Et le corps de réponse contient:
      """json
      {
        "your_completion_rate": 58,
        "category_avg": 62,
        "platform_avg": 60,
        "performance": "below_category_avg",
        "percentile": 45
      }
      """

  # Événements trackés

  Scénario: POST /api/v1/events/track - Tracking événements utilisateur
    Étant donné qu'un utilisateur interagit avec un audio-guide
    Quand un événement se produit
    Alors il est tracké avec les données suivantes:
      | événement              | données                                    |
      | audio_guide_started    | audio_guide_id, mode, user_id              |
      | sequence_completed     | sequence_id, completion_rate, duration     |
      | audio_guide_completed  | audio_guide_id, total_time, sequences_count|
      | point_gps_triggered    | point_id, distance, auto_or_manual         |
      | point_gps_missed       | point_id, distance, action_taken           |

  Scénario: Exemple événement audio_guide_started
    Quand un audio-guide démarre
    Alors l'événement suivant est envoyé:
      """json
      {
        "event_type": "audio_guide_started",
        "timestamp": "2026-01-22T14:00:00Z",
        "user_id": "user_456",
        "audio_guide_id": "ag_123",
        "mode": "voiture",
        "device": "ios",
        "location": {"lat": 43.1234, "lon": 2.5678}
      }
      """

  Scénario: Exemple événement point_gps_triggered
    Quand un point GPS déclenche une séquence
    Alors l'événement suivant est envoyé:
      """json
      {
        "event_type": "point_gps_triggered",
        "timestamp": "2026-01-22T14:05:30Z",
        "user_id": "user_456",
        "audio_guide_id": "ag_123",
        "sequence_id": "seq_2",
        "trigger_type": "gps_auto",
        "distance_to_point": 25,
        "speed_kmh": 28
      }
      """

  # Export données

  Scénario: GET /api/v1/creators/me/audio-guides/{id}/export - Export CSV
    Étant donné un audio-guide avec historique complet
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/export?format=csv"
    Alors le code HTTP de réponse est 200
    Et le Content-Type est "text/csv"
    Et le fichier CSV contient:
      | user_id  | sequence_id | started_at          | completed_at        | completion_rate |
      | user_123 | seq_1       | 2026-01-22 14:10:00 | 2026-01-22 14:12:15 | 100             |
      | user_123 | seq_2       | 2026-01-22 14:12:20 | 2026-01-22 14:14:08 | 100             |

  Scénario: Export JSON pour analyse externe
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/export?format=json"
    Alors le code HTTP de réponse est 200
    Et le Content-Type est "application/json"
    Et le fichier JSON contient toutes les métriques détaillées

  # Cache et performance

  Scénario: Cache Redis pour stats fréquemment consultées
    Étant donné que les stats globales d'un audio-guide sont en cache Redis
    Quand je fais un GET sur "/api/v1/creators/me/audio-guides/ag_123/stats"
    Alors les stats sont récupérées depuis Redis (pas PostgreSQL)
    Et le temps de réponse est < 50ms
    Et le cache a un TTL de 5 minutes

  Scénario: Invalidation cache lors de nouvelles écoutes
    Étant donné que les stats sont en cache Redis
    Quand une nouvelle écoute complète est enregistrée
    Alors le cache Redis est invalidé pour cet audio-guide
    Et le prochain GET recalcule les stats depuis PostgreSQL

  Scénario: Pré-calcul stats quotidien (job batch)
    Étant donné que le job batch s'exécute chaque nuit à 3h
    Quand le job démarre
    Alors pour chaque audio-guide actif:
      - Les stats sont calculées depuis les événements bruts
      - Les résultats sont stockés dans audio_guide_stats_daily
      - Les agrégations (7j, 30j, 90j) sont pré-calculées
    Et les requêtes du lendemain sont instantanées (lecture table pré-calculée)
