# language: fr
Fonctionnalité: Synchronisation actions offline
  En tant qu'utilisateur
  Je veux que mes actions offline soient synchronisées quand je me reconnecte
  Afin de ne perdre aucune interaction même sans connexion

  Contexte:
    Étant donné que j'utilise l'application RoadWave

  # ===== ACTIONS STOCKÉES LOCALEMENT =====

  Scénario: Like d'un contenu en mode offline
    Étant donné que je n'ai aucune connexion Internet
    Quand je like un contenu téléchargé
    Alors l'action est enregistrée localement dans SQLite:
      ```sql
      INSERT INTO pending_actions (type, content_id, created_at)
      VALUES ('like', 'abc123', '2025-06-15 14:30:00');
      ```
    Et l'UI affiche immédiatement le like (optimistic update)

  Scénario: Unlike d'un contenu en mode offline
    Étant donné que je n'ai aucune connexion Internet
    Et que j'avais liké un contenu
    Quand je retire mon like
    Alors l'action est enregistrée localement:
      ```sql
      INSERT INTO pending_actions (type, content_id, created_at)
      VALUES ('unlike', 'abc123', '2025-06-15 14:35:00');
      ```
    Et l'UI retire immédiatement le like

  Scénario: Abonnement à un créateur en mode offline
    Étant donné que je n'ai aucune connexion Internet
    Quand je m'abonne à un créateur
    Alors l'action est enregistrée localement:
      ```sql
      INSERT INTO pending_actions (type, creator_id, created_at)
      VALUES ('subscribe', 'creator456', '2025-06-15 14:40:00');
      ```
    Et l'UI affiche immédiatement "Abonné ✓"

  Scénario: Désabonnement d'un créateur en mode offline
    Étant donné que je n'ai aucune connexion Internet
    Et que j'étais abonné à un créateur
    Quand je me désabonne
    Alors l'action est enregistrée localement:
      ```sql
      INSERT INTO pending_actions (type, creator_id, created_at)
      VALUES ('unsubscribe', 'creator456', '2025-06-15 14:45:00');
      ```
    Et l'UI affiche "S'abonner"

  Scénario: Signalement d'un contenu en mode offline
    Étant donné que je n'ai aucune connexion Internet
    Quand je signale un contenu pour "Contenu inapproprié"
    Alors l'action est enregistrée localement:
      ```sql
      INSERT INTO pending_actions (type, content_id, reason, created_at)
      VALUES ('report', 'abc123', 'Contenu inapproprié', '2025-06-15 14:50:00');
      ```
    Et je vois "Signalement enregistré. Sera envoyé à la reconnexion."

  Scénario: Progression audio-guide en mode offline
    Étant donné que je n'ai aucune connexion Internet
    Et que j'écoute un audio-guide multi-séquences
    Quand je termine la séquence 3/10
    Alors la progression est enregistrée localement:
      ```sql
      INSERT INTO pending_actions (type, guide_id, sequence_id, created_at)
      VALUES ('guide_progress', 'guide789', 'seq003', '2025-06-15 15:00:00');
      ```
    Et ma progression est sauvegardée

  Scénario: Multiple actions offline stockées en queue
    Étant donné que je n'ai aucune connexion Internet pendant 2 jours
    Quand j'effectue plusieurs actions:
      | action       | cible       |
      | like         | contenu A   |
      | like         | contenu B   |
      | subscribe    | créateur X  |
      | unlike       | contenu C   |
      | report       | contenu D   |
    Alors les 5 actions sont stockées dans pending_actions
    Et elles seront synchronisées dans l'ordre à la reconnexion

  # ===== SYNCHRONISATION AUTOMATIQUE =====

  Scénario: Détection reconnexion Internet
    Étant donné que j'étais en mode offline
    Quand l'app détecte une reconnexion Internet
    Alors le processus de synchronisation démarre automatiquement
    Et je vois une notification "Synchronisation en cours..."

  Scénario: Récupération queue locale pendant sync
    Étant donné que la synchronisation démarre
    Quand l'app récupère les actions en attente
    Alors une requête SQL est exécutée:
      ```sql
      SELECT * FROM pending_actions ORDER BY created_at ASC;
      ```
    Et toutes les actions sont récupérées dans l'ordre chronologique

  Scénario: Envoi batch API des actions
    Étant donné que 15 actions sont en attente
    Quand le batch est envoyé au backend
    Alors une requête POST /sync/actions est faite:
      ```json
      {
        "actions": [
          {"type": "like", "content_id": "abc123", "timestamp": "2025-06-15T14:30:00Z"},
          {"type": "subscribe", "creator_id": "creator456", "timestamp": "2025-06-15T14:40:00Z"},
          {"type": "unlike", "content_id": "def789", "timestamp": "2025-06-15T14:50:00Z"},
          ...
        ]
      }
      ```
    Et toutes les actions sont groupées en une seule requête

  Scénario: Backend traite chaque action
    Étant donné que le backend reçoit le batch d'actions
    Quand il traite chaque action
    Alors pour chaque action:
      | étape                           | détail                                    |
      | Validation                      | Vérifier user_id, content_id valides      |
      | Vérification existence          | Contenu/créateur existe toujours ?        |
      | Application action              | INSERT/UPDATE/DELETE en base              |
      | Mise à jour compteurs           | Likes, abonnés, etc.                      |
      | Impact sur algorithme           | Mise à jour jauges si nécessaire          |

  Scénario: Confirmation réception et suppression queue locale
    Étant donné que le backend a traité toutes les actions avec succès
    Quand la confirmation est reçue par l'app
    Alors les actions sont supprimées de la queue locale:
      ```sql
      DELETE FROM pending_actions WHERE id IN (1, 2, 3, ..., 15);
      ```
    Et la table pending_actions est vidée

  Scénario: Toast confirmation synchronisation
    Étant donné que 15 actions ont été synchronisées
    Quand la synchronisation se termine
    Alors je vois un toast:
      """
      ✅ Synchronisation réussie

      3 likes, 1 abonnement et 1 signalement synchronisés.
      """

  Scénario: Synchronisation silencieuse si peu d'actions
    Étant donné que j'ai seulement 2 actions en attente
    Quand la synchronisation se termine
    Alors aucun toast n'est affiché (sync silencieuse)
    Et l'expérience reste fluide
    Mais je peux voir le détail dans l'historique des syncs

  # ===== GESTION ERREURS SYNC =====

  Scénario: Échec synchronisation - Retry automatique
    Étant donné que la synchronisation échoue (erreur réseau)
    Quand l'échec est détecté
    Alors un retry automatique est programmé dans 30 secondes
    Et les actions restent dans pending_actions

  Scénario: 3 tentatives échouées - Notification utilisateur
    Étant donné que 3 tentatives de synchronisation ont échoué
    Quand la 3ème tentative échoue
    Alors je reçois une notification:
      """
      ⚠️ Impossible de synchroniser vos actions

      15 actions en attente de synchronisation.
      Vérifiez votre connexion et réessayez.

      [Réessayer maintenant]  [Plus tard]
      ```

  Scénario: Actions conservées jusqu'à sync réussie
    Étant donné que la synchronisation échoue plusieurs fois
    Quand les tentatives continuent d'échouer
    Alors les actions restent dans pending_actions
    Et aucune action n'est perdue
    Et elles seront envoyées dès que la connexion sera stable

  Scénario: Rétention max 7 jours - Purge automatique
    Étant donné qu'une action est en attente depuis 7 jours
    Quand le système détecte cette ancienneté
    Alors l'action est automatiquement supprimée de la queue
    Et je vois "1 action trop ancienne supprimée (>7 jours)"
    Et cela évite une queue infinie

  Scénario: Justification rétention 7 jours
    Étant donné qu'un utilisateur ne se connecte jamais pendant 2 semaines
    Quand ses actions ont >7 jours
    Alors elles sont purgées automatiquement
    Car après 7 jours, l'action perd sa pertinence
    Et évite une queue qui grandit indéfiniment

  Scénario: Retry manuel après échec
    Étant donné que la synchronisation a échoué
    Quand je clique sur "Réessayer maintenant"
    Alors une nouvelle tentative de synchronisation est lancée immédiatement
    Et si elle réussit, les actions sont synchronisées

  # ===== CONFLITS CONTENUS SUPPRIMÉS =====

  Scénario: Backend retourne contenus supprimés
    Étant donné que j'ai liké un contenu offline
    Mais que le contenu a été supprimé entre temps
    Quand le backend traite la synchronisation
    Alors il retourne:
      ```json
      {
        "status": "partial_success",
        "deleted_content_ids": [123, 456],
        "failed_actions": [
          {"type": "like", "content_id": "123", "reason": "content_deleted"}
        ]
      }
      ```

  Scénario: App supprime fichiers locaux contenus supprimés
    Étant donné que le backend retourne deleted_content_ids: [123, 456]
    Quand l'app traite la réponse
    Alors elle supprime les fichiers locaux des contenus 123 et 456
    Et libère l'espace disque
    Et les actions associées sont retirées de la queue

  Scénario: Contenu supprimé en cours d'écoute
    Étant donné que j'écoute le contenu 123 en offline
    Et que la sync détecte que le contenu a été supprimé
    Quand la lecture actuelle se termine
    Alors l'app attend 2 secondes
    Et passe automatiquement au contenu suivant
    Et le fichier du contenu 123 est supprimé en arrière-plan

  Scénario: Toast notification contenu retiré
    Étant donné que 2 contenus téléchargés ont été supprimés
    Quand la synchronisation se termine
    Alors je vois un toast:
      """
      🗑️ 2 contenus téléchargés ont été retirés

      Raison: Violation des règles de la plateforme
      """

  Scénario: Contenu modéré après téléchargement
    Étant donné que j'ai téléchargé un contenu qui est ensuite modéré
    Quand la synchronisation détecte la modération
    Alors le contenu est immédiatement supprimé du device
    Et je ne peux plus l'écouter
    Et cela garantit la conformité même offline

  # ===== JUSTIFICATIONS =====

  Scénario: Justification pas de conflit possible
    Étant donné que les actions offline sont unilatérales (likes, abonnements)
    Quand elles sont synchronisées
    Alors il n'y a pas de conflit de version possible
    Car l'utilisateur ajoute/retire simplement des préférences
    Et pas de merge complexe nécessaire

  Scénario: Justification UX fluide offline
    Étant donné que toutes les actions fonctionnent offline
    Quand l'utilisateur interagit sans connexion
    Alors l'expérience est identique au mode online
    Et l'utilisateur n'est pas bloqué
    Et peut utiliser l'app normalement

  Scénario: Justification batch = Économie requêtes
    Étant donné que 15 actions sont en attente
    Quand elles sont synchronisées en batch
    Alors 1 seule requête HTTP est envoyée (vs 15 si individuelles)
    Et cela économise la bande passante et la batterie
    Et réduit la charge serveur

  Scénario: Justification conformité modération offline
    Étant donné qu'un contenu illégal est modéré pendant qu'un user est offline
    Quand le user se reconnecte
    Alors le contenu est immédiatement supprimé de son device
    Et cela garantit que les contenus illégaux disparaissent même offline

  # ===== STATISTIQUES ET MONITORING =====

  Scénario: Historique synchronisations
    Étant donné que j'accède à "Paramètres > Synchronisation"
    Quand je consulte l'historique
    Alors je vois:
      | date                | actions sync | statut    |
      | 15/06/2025 14:30:00 | 15           | Réussi ✅ |
      | 14/06/2025 09:15:00 | 7            | Réussi ✅ |
      | 13/06/2025 18:45:00 | 3            | Échec ❌  |

  Scénario: Détail d'une synchronisation
    Étant donné que je clique sur une ligne de l'historique
    Quand le détail s'affiche
    Alors je vois:
      ```
      Synchronisation du 15/06/2025 14:30:00

      Actions synchronisées:
      • 3 likes
      • 1 abonnement
      • 1 signalement
      • 10 progressions audio-guides

      Durée: 1.2s
      Statut: Réussi ✅
      ```

  Scénario: Compteur actions en attente visible
    Étant donné que j'ai 12 actions en attente de synchronisation
    Quand j'accède à l'onglet Profil
    Alors je vois un badge "12" sur l'icône de synchronisation
    Et je sais qu'il y a des actions en attente

  Scénario: Synchronisation manuelle forcée
    Étant donné que je veux forcer une synchronisation immédiate
    Quand je vais dans "Paramètres > Synchronisation"
    Et que je clique sur "Synchroniser maintenant"
    Alors la synchronisation démarre immédiatement
    Et toutes les actions en attente sont envoyées

  Scénario: Statistiques utilisateur - Syncs effectuées
    Étant donné que j'accède à mes statistiques
    Quand je consulte la section Synchronisation
    Alors je vois:
      | métrique                        | valeur |
      | Synchronisations depuis début   | 87     |
      | Actions synchronisées total     | 1,234  |
      | Taux de succès                  | 94%    |
      | Dernière sync                   | Il y a 2h|

  Scénario: Statistiques admin - Volume synchronisations
    Étant donné qu'un admin consulte les métriques de synchronisation
    Quand il accède au dashboard
    Alors il voit:
      | métrique                          | valeur      |
      | Synchronisations/jour             | 45,678      |
      | Actions synchronisées/jour        | 234,567     |
      | Taux succès sync                  | 96.5%       |
      | Temps moyen traitement batch      | 0.8s        |
      | Actions en attente (global)       | 12,345      |

  Scénario: Alerte admin si taux échec sync >10%
    Étant donné que le taux d'échec sync dépasse 10%
    Quand le système détecte cette anomalie
    Alors une alerte est envoyée:
      """
      ⚠️ Taux échec synchronisation anormal: 12.3%

      Échecs aujourd'hui: 5,621 / 45,678 syncs
      Causes principales:
      - Timeout serveur: 3,245
      - Erreur réseau client: 1,876
      - Données invalides: 500

      Action recommandée: Vérifier charge serveur + logs erreurs
      """

  # ===== TESTS PERFORMANCE =====

  Scénario: Synchronisation rapide <2s
    Étant donné que j'ai 20 actions en attente
    Quand la synchronisation démarre
    Alors le traitement prend <2 secondes
    Et je ne remarque aucun ralentissement de l'app

  Scénario: Synchronisation de gros batch (100 actions)
    Étant donné que je n'ai pas synchronisé pendant 1 semaine
    Et que j'ai 100 actions en attente
    Quand la synchronisation démarre
    Alors le batch de 100 actions est traité en <5 secondes
    Et toutes les actions sont synchronisées avec succès

  Scénario: Gestion charge serveur - 10 000 syncs simultanées
    Étant donné que 10 000 utilisateurs se reconnectent simultanément
    Quand chacun envoie un batch de 20 actions
    Alors le serveur traite 200 000 actions
    Et grâce au traitement asynchrone (queue Redis), le temps de réponse reste <3s
    Et aucun timeout n'est constaté

  Scénario: Stockage SQLite optimisé
    Étant donné que la table pending_actions stocke des centaines d'actions
    Quand des requêtes sont exécutées
    Alors la table est indexée sur created_at
    Et les requêtes SELECT et DELETE sont instantanées (<10ms)
    Et l'expérience utilisateur reste fluide

  Scénario: Nettoyage automatique table pending_actions
    Étant donné que la table pending_actions grossit avec le temps
    Quand les actions sont synchronisées et supprimées
    Alors la table est automatiquement optimisée (VACUUM sur SQLite)
    Et l'espace disque est libéré
    Et les performances restent optimales

  # ===== EDGE CASES =====

  Scénario: Action dupliquée - Idempotence
    Étant donné que j'ai liké un contenu offline
    Et que la sync échoue et retry
    Quand le backend reçoit 2 fois le même like
    Alors il applique l'idempotence (1 seul like enregistré)
    Et le compteur de likes n'est pas faussé

  Scénario: Séquence like/unlike offline
    Étant donné que j'ai liké puis unliké un contenu offline
    Quand les 2 actions sont synchronisées
    Alors le backend applique les 2 actions dans l'ordre
    Et le résultat final est "pas de like" (état correct)

  Scénario: Abonnement puis désabonnement offline
    Étant donné que je me suis abonné puis désabonné d'un créateur offline
    Quand les 2 actions sont synchronisées
    Alors le backend applique les 2 actions dans l'ordre
    Et le résultat final est "pas abonné"
    Et les jauges évoluent correctement (+5% puis -5% = 0% net)

  Scénario: Créateur supprimé pendant offline
    Étant donné que je me suis abonné à un créateur offline
    Mais que le créateur a supprimé son compte entre temps
    Quand la sync traite l'abonnement
    Alors le backend retourne "creator_deleted"
    Et l'action est ignorée silencieusement
    Et aucune erreur n'est affichée à l'utilisateur
