import { getVaultTokens, updateVaultAccess, type VaultTokenSet } from 'officerdb';
import { refreshGrant, pick, expiryFrom } from './broker';

// Read-side of the brokered Vaultwarden token: hand out a currently-valid access token, refreshing it
// server-side (with the stored refresh token) when it's near expiry. Shared by the HTTP proxy and the
// notifications-WS proxy so both inject a fresh token. The device never sees any of this.

const REFRESH_SKEW_MS = 60_000; // refresh a bit before expiry to avoid racing a 401

/** Renew the access token from the stored refresh token; persist and return it, or null on failure. */
export async function refreshAccess(userId: number, ts: VaultTokenSet): Promise<string | null> {
  const r = await refreshGrant(ts.refreshToken, ts.clientId ?? 'mobile');
  if (!r.ok) return null;
  const access = pick(r.data, 'access_token');
  const refresh = pick(r.data, 'refresh_token');
  if (typeof access !== 'string') return null;
  await updateVaultAccess(
    userId,
    access,
    typeof refresh === 'string' ? refresh : ts.refreshToken,
    expiryFrom(r.data, Date.now()),
  );
  return access;
}

/** A currently-valid Vaultwarden access token for the owner, or null if none is stored. */
export async function getValidAccessToken(userId: number): Promise<string | null> {
  const ts = await getVaultTokens(userId);
  if (!ts) return null;
  if (ts.expiresAt && ts.expiresAt.getTime() < Date.now() + REFRESH_SKEW_MS) {
    return (await refreshAccess(userId, ts)) ?? ts.accessToken;
  }
  return ts.accessToken;
}
