// src/lib/onboarding/activation/snapshot.ts — lecture serveur de l'état
// d'activation, appelée par le layout (app) et par Settings → Compte.
import "server-only";

import { cache } from "react";
import { getActiveOrgId, getActiveUserId } from "@/lib/active-org";
import { getSitesForActiveOrg, hasFullSiteAccess } from "@/lib/sites/access";
import { getActiveSiteId } from "@/lib/sites/active-site";
import { deriveActivationFlags } from "./derive";
import { isActivationDismissed } from "./dismiss";
import type { ActivationSnapshot } from "./types";

/**
 * État d'activation dérivé côté serveur, dédupé par requête.
 *
 * Remplace l'ancienne lecture client (`getActivationAction` appelée au montage,
 * à chaque navigation et sur `window.focus`) : un seul passage par rendu, dont
 * les seuls lecteurs sont des RSC.
 *
 * Le masquage NE court-circuite PAS la dérivation. Il l'a fait un temps, pour
 * économiser six EXISTS par navigation, et c'était un contresens : le gate du
 * wizard (src/lib/onboarding/wizard-gate.ts) est devenu un second lecteur des
 * drapeaux, et sans eux il n'avait d'autre choix que de laisser passer. Masquer
 * la carte — un bouton libellé comme un simple masquage d'affichage — revenait
 * alors à désactiver DÉFINITIVEMENT le parcours guidé, pour toute l'org, alors
 * que le report explicite, lui, est soigneusement borné à la session.
 * `dismissed` ne pilote donc plus QUE l'affichage de la carte.
 *
 * Le vrai remède à la dépense (la dérivation tourne à vie, même une fois
 * l'activation terminée) est un marqueur d'activation terminée en base, pas ce
 * court-circuit-là.
 *
 * Fail-silent : la checklist disparaît plutôt que de casser le rendu de l'app.
 * En cas de disparition inattendue, chercher `[activation] snapshot failed:`.
 */
export const getActivationSnapshot = cache(
  async (): Promise<ActivationSnapshot | null> => {
    try {
      const [userId, orgId] = await Promise.all([
        getActiveUserId(),
        getActiveOrgId(),
      ]);
      const dismissed = await isActivationDismissed(userId, orgId);
      // La checklist est dérivée par site. `getSitesForActiveOrg` filtre déjà
      // par accès (et est elle-même `cache()`-ée, donc gratuite quand le layout
      // l'a déjà appelée) : un membre ne dérivera jamais sur un site qu'il ne
      // voit pas. `getActiveSiteId` renvoie "" sur une liste vide — on ne
      // l'appelle donc qu'avec au moins un site.
      // `hasFullSiteAccess` s'adosse au même `currentCaller` mis en cache que le
      // layout (app) interroge déjà : aucune requête supplémentaire.
      const [sites, canCreateSite] = await Promise.all([
        getSitesForActiveOrg(),
        hasFullSiteAccess(),
      ]);
      const siteId = sites.length
        ? await getActiveSiteId(sites.map((s) => s.id))
        : null;
      return {
        flags: await deriveActivationFlags(orgId, siteId),
        dismissed,
        hasAccessibleSite: siteId !== null,
        canCreateSite,
      };
    } catch (err) {
      console.error("[activation] snapshot failed:", err);
      return null;
    }
  },
);
