/**
 * Phoenix ID — the typed surface commands use. Every route the account backend
 * exposes is a function here; no command builds a URL or reads a token itself.
 */
import { phoenixRequest, PhoenixApiError, readSession, writeSession } from './client.js';
export { PHOENIX_ID_BASE, PhoenixApiError, clearSession, readSession, sessionFilePath, writeSession, } from './client.js';
export function startDeviceAuthorization() {
    return phoenixRequest('POST', '/api/v1/auth/device/authorization', {
        auth: false,
        body: {},
    });
}
export async function pollDeviceToken(deviceCode) {
    try {
        return await phoenixRequest('POST', '/api/v1/auth/device/token', {
            auth: false,
            body: {
                grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
                device_code: deviceCode,
            },
        });
    }
    catch (err) {
        if (!(err instanceof PhoenixApiError))
            throw err;
        // The server encodes poll state in the error body (RFC 8628 §3.5).
        if (err.message.includes('authorization_pending'))
            return { status: 'pending' };
        if (err.message.includes('slow_down'))
            return { status: 'slow_down' };
        if (err.message.includes('expired_token'))
            return { status: 'expired' };
        if (err.message.includes('access_denied'))
            return { status: 'denied' };
        throw err;
    }
}
export function fetchWhoAmI(token) {
    return phoenixRequest('GET', '/api/v1/auth/me', { token });
}
/**
 * Best-effort fill of the session's hosted avatar (PHNX-3547): sessions written
 * before the CLI tracked avatars have none, so ask `/api/v1/auth/me` and merge
 * a hosted `avatar_url` into the persisted session — future publishes then
 * stamp the OAuth profile image instead of only a Gravatar hash. A no-op when
 * signed out, when an avatar is already stored, or when the server exposes
 * none; network/server failures are swallowed (the share attribution falls
 * back to Gravatar/initials either way).
 */
export async function refreshSessionAvatar() {
    const session = readSession();
    if (!session || session.avatarUrl)
        return;
    try {
        const me = await fetchWhoAmI();
        const hosted = me.avatar_url?.trim();
        if (hosted && /^https:\/\//i.test(hosted)) {
            writeSession({ ...session, avatarUrl: hosted });
        }
    }
    catch {
        // Offline or server without the field — the Gravatar fallback covers it.
    }
}
export const listSpaces = () => phoenixRequest('GET', '/api/v1/spaces');
export const createSpace = (input) => phoenixRequest('POST', '/api/v1/spaces', { body: input });
export const getSpace = (id) => phoenixRequest('GET', `/api/v1/spaces/${encodeURIComponent(id)}`);
export const listSpaceMembers = (id) => phoenixRequest('GET', `/api/v1/spaces/${encodeURIComponent(id)}/members`);
export const createSpaceInvite = (id, input) => phoenixRequest('POST', `/api/v1/spaces/${encodeURIComponent(id)}/invites`, {
    body: input,
});
export const listSpaceInvites = (id) => phoenixRequest('GET', `/api/v1/spaces/${encodeURIComponent(id)}/invites`);
export const revokeSpaceInvite = (id, inviteId) => phoenixRequest('DELETE', `/api/v1/spaces/${encodeURIComponent(id)}/invites/${encodeURIComponent(inviteId)}`);
export const updateSpaceMemberRole = (id, userId, role) => phoenixRequest('PATCH', `/api/v1/spaces/${encodeURIComponent(id)}/members/${encodeURIComponent(userId)}`, {
    body: { role },
});
export const removeSpaceMember = (id, userId) => phoenixRequest('DELETE', `/api/v1/spaces/${encodeURIComponent(id)}/members/${encodeURIComponent(userId)}`);
export const deleteSpace = (id) => phoenixRequest('DELETE', `/api/v1/spaces/${encodeURIComponent(id)}`);
export const fetchSubscription = (agent = 'agents-cli') => phoenixRequest('GET', `/api/v1/billing/subscription?agent=${encodeURIComponent(agent)}`);
// ─── Helpers shared by the commands ──────────────────────────────────────────
/** `Design Team` → `design-team`; the slug a space gets when the user gives only a name. */
export function slugify(name) {
    return name
        .trim()
        .toLowerCase()
        .replace(/[^a-z0-9]+/g, '-')
        .replace(/^-+|-+$/g, '')
        .slice(0, 63);
}
/** Resolve a space by id, slug, or name from a list the caller already fetched. */
export function resolveSpaceFromList(spaces, ref) {
    if (!ref)
        return spaces.length === 1 ? spaces[0] : null;
    const needle = ref.trim().toLowerCase();
    return (spaces.find((s) => s.id === ref) ??
        spaces.find((s) => s.slug.toLowerCase() === needle) ??
        spaces.find((s) => s.name.toLowerCase() === needle) ??
        null);
}
/** Resolve a member by email or user id from a list the caller already fetched. */
export function resolveMemberFromList(members, ref) {
    const needle = ref.trim().toLowerCase();
    return (members.find((m) => m.user_id === ref) ??
        members.find((m) => m.email.toLowerCase() === needle) ??
        null);
}
