// Auto-generated by FORGE - DO NOT EDIT
// Auth store for Svelte 5 with localStorage persistence and refresh token support
import { getForgeClient } from "@forge-rs/svelte";

interface User {
  id: string;
  email: string;
  name?: string;
}

interface AuthState {
  token: string | null;
  refreshToken: string | null;
  user: User | null;
}

const AUTH_KEY = "forge_auth";

function loadFromStorage(): AuthState {
  if (typeof localStorage === "undefined") {
    return { token: null, refreshToken: null, user: null };
  }
  const stored = localStorage.getItem(AUTH_KEY);
  if (!stored) {
    return { token: null, refreshToken: null, user: null };
  }
  try {
    return JSON.parse(stored);
  } catch {
    return { token: null, refreshToken: null, user: null };
  }
}

function saveToStorage(state: AuthState): void {
  if (typeof localStorage === "undefined") return;
  if (state.token) {
    localStorage.setItem(AUTH_KEY, JSON.stringify(state));
  } else {
    localStorage.removeItem(AUTH_KEY);
  }
}

class AuthStore {
  #state: AuthState = $state(loadFromStorage());
  #refreshInterval: ReturnType<typeof setInterval> | null = null;
  #apiUrl: string = "";

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

  get refreshToken(): string | null {
    return this.#state.refreshToken;
  }

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

  get isAuthenticated(): boolean {
    return this.#state.token !== null;
  }

  /** Initialize periodic refresh. Call once from your root layout. */
  startRefreshLoop(apiUrl: string, intervalMs = 40 * 60 * 1000): void {
    this.#apiUrl = apiUrl;
    this.stopRefreshLoop();
    this.#refreshInterval = setInterval(() => {
      if (this.isAuthenticated) {
        this.tryRefresh();
      }
    }, intervalMs);
  }

  stopRefreshLoop(): void {
    if (this.#refreshInterval) {
      clearInterval(this.#refreshInterval);
      this.#refreshInterval = null;
    }
  }

  setAuth(token: string, refreshToken: string, user: User): void {
    this.#state = { token, refreshToken, user };
    saveToStorage(this.#state);
    getForgeClient()?.reconnect();
  }

  updateTokens(token: string, refreshToken: string): void {
    this.#state = { ...this.#state, token, refreshToken };
    saveToStorage(this.#state);
  }

  updateUser(user: User): void {
    this.#state = { ...this.#state, user };
    saveToStorage(this.#state);
  }

  clearAuth(): void {
    this.#state = { token: null, refreshToken: null, user: null };
    saveToStorage(this.#state);
    this.stopRefreshLoop();
    getForgeClient()?.reconnect();
  }

  /** Attempt to refresh tokens using the backend refresh mutation.
   *  Only clears auth on definitive failures (401/403). Network errors
   *  are silently ignored so transient issues don't force logouts. */
  async tryRefresh(): Promise<boolean> {
    if (!this.#state.refreshToken || !this.#apiUrl) return false;
    try {
      const res = await fetch(`${this.#apiUrl}/_api/rpc/refresh`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          args: { refresh_token: this.#state.refreshToken },
        }),
      });
      if (!res.ok) {
        if (res.status === 401 || res.status === 403) {
          this.clearAuth();
        }
        return false;
      }
      const envelope = await res.json();
      if (envelope.success && envelope.data) {
        this.updateTokens(
          envelope.data.access_token,
          envelope.data.refresh_token,
        );
        return true;
      }
      this.clearAuth();
      return false;
    } catch {
      // Network error - keep tokens and retry later
      return false;
    }
  }

  #refreshPromise: Promise<boolean> | null = null;

  /** Call from ForgeProvider's onAuthError callback.
   *  Coalesces concurrent calls so multiple 401s don't race. */
  async handleAuthError(): Promise<void> {
    if (!this.isAuthenticated) return;
    if (!this.#refreshPromise) {
      this.#refreshPromise = this.tryRefresh().finally(() => {
        this.#refreshPromise = null;
      });
    }
    const ok = await this.#refreshPromise;
    if (!ok) this.clearAuth();
  }
}

export const auth = new AuthStore();

export function getToken(): string | null {
  return auth.token;
}
