import { resolveOAuthClientCredentials } from "./oauth-client-config.js";
const DEFAULT_REFRESH_WINDOW_MS = 6e4;
const inFlightRefreshes = /* @__PURE__ */ new Map();
async function refreshCredentialsIfNeeded(input, deps) {
  const log = deps?.logger ?? (() => {
  });
  if (typeof input.adapter.refreshCredentials !== "function") {
    return { refreshed: false, credentials: input.credentials };
  }
  const refreshWindow = input.refreshWindowMs ?? DEFAULT_REFRESH_WINDOW_MS;
  if (!input.force && !shouldRefresh(input.credentials, refreshWindow)) {
    return { refreshed: false, credentials: input.credentials };
  }
  const existing = inFlightRefreshes.get(input.channelId);
  if (existing) return existing;
  const refreshCredentials = input.adapter.refreshCredentials.bind(input.adapter);
  const refreshPromise = runRefresh(input, refreshCredentials, deps, log).finally(() => {
    inFlightRefreshes.delete(input.channelId);
  });
  inFlightRefreshes.set(input.channelId, refreshPromise);
  return refreshPromise;
}
async function runRefresh(input, refreshCredentials, deps, log) {
  let oauthClient;
  if (deps?.credentialsService) {
    try {
      const raw = await resolveOAuthClientCredentials(
        deps.credentialsService,
        input.adapter.providerKey,
        { tenantId: input.scope.tenantId, organizationId: input.scope.organizationId }
      );
      oauthClient = safeParseOAuthClient(raw);
    } catch (resolveErr) {
      log(
        "[communication_channels] resolving OAuth client config failed:",
        resolveErr instanceof Error ? resolveErr.message : resolveErr
      );
    }
  }
  let result;
  try {
    result = await refreshCredentials({
      channelId: input.channelId,
      credentials: input.credentials,
      scope: input.scope,
      oauthClient
    });
  } catch (err) {
    log("[communication_channels] refreshCredentials failed:", err instanceof Error ? err.message : err);
    return { refreshed: false, credentials: input.credentials };
  }
  const next = result?.credentials ?? input.credentials;
  if (deps?.credentialsService?.save) {
    try {
      await deps.credentialsService.save(
        `channel_${input.adapter.providerKey}`,
        result.expiresAt ? { ...next, expiresAt: result.expiresAt.toISOString() } : next,
        input.scope
      );
    } catch (saveErr) {
      log("[communication_channels] persisting refreshed credentials failed:", saveErr instanceof Error ? saveErr.message : saveErr);
    }
  }
  return { refreshed: true, credentials: next };
}
function shouldRefresh(credentials, windowMs) {
  const expiresAtRaw = credentials?.expiresAt;
  if (!expiresAtRaw) return false;
  const expiresAt = parseExpiresAt(expiresAtRaw);
  if (!expiresAt) return false;
  return expiresAt.getTime() - Date.now() <= windowMs;
}
function parseExpiresAt(raw) {
  if (raw instanceof Date) return Number.isFinite(raw.getTime()) ? raw : null;
  if (typeof raw === "string" || typeof raw === "number") {
    const date = new Date(raw);
    return Number.isFinite(date.getTime()) ? date : null;
  }
  return null;
}
function safeParseOAuthClient(raw) {
  if (!raw || typeof raw !== "object") return void 0;
  const record = raw;
  const clientId = typeof record.clientId === "string" ? record.clientId : void 0;
  if (!clientId) return void 0;
  const clientSecret = typeof record.clientSecret === "string" ? record.clientSecret : void 0;
  const scopes = Array.isArray(record.scopes) ? record.scopes.filter((value) => typeof value === "string") : void 0;
  return {
    clientId,
    ...clientSecret !== void 0 ? { clientSecret } : {},
    ...scopes !== void 0 ? { scopes } : {}
  };
}
export {
  refreshCredentialsIfNeeded
};
//# sourceMappingURL=credential-refresh.js.map
