import { useSyncExternalStore } from "react";
import * as Sentry from "@sentry/react";
import type { User } from "@rubis/shared";

/**
 * Auth store — token en mémoire seulement (pas localStorage).
 * Le refresh token vit en cookie httpOnly côté API, invisible ici.
 * Cf. ADR-017 et /docs/tech/frontend.md §7.
 *
 * Sentry user context : on attache `user.id` (pas l'email, pas le nom
 * — minimisation PII) sur les events Sentry au login, et on clear au
 * logout. Permet de corréler une stack trace à un user spécifique sans
 * leak d'info personnelle.
 */

type AuthState = {
  accessToken: string | null;
  user: User | null;
};

class AuthStore {
  private state: AuthState = { accessToken: null, user: null };
  private listeners = new Set<() => void>();

  getSnapshot = (): AuthState => this.state;

  get token(): string | null {
    return this.state.accessToken;
  }

  get user(): User | null {
    return this.state.user;
  }

  isAuthenticated(): boolean {
    return this.state.accessToken !== null;
  }

  setSession(accessToken: string, user: User): void {
    this.state = { accessToken, user };
    Sentry.setUser({ id: user.id });
    this.notify();
  }

  clear(): void {
    this.state = { accessToken: null, user: null };
    Sentry.setUser(null);
    this.notify();
  }

  subscribe = (fn: () => void): (() => void) => {
    this.listeners.add(fn);
    return () => {
      this.listeners.delete(fn);
    };
  };

  private notify(): void {
    this.listeners.forEach((fn) => fn());
  }
}

export const authStore = new AuthStore();

/** Hook React pour s'abonner à l'état d'auth. */
export function useAuth(): AuthState {
  return useSyncExternalStore(authStore.subscribe, authStore.getSnapshot, authStore.getSnapshot);
}
