/**
 * CLI Authentication
 *
 * Handles storing and retrieving auth tokens for the CLI.
 * Tokens are stored in ~/.quickback/credentials.json
 *
 * The CLI uses Device Authorization flow which creates a real Better Auth session.
 * The CLI stores a bearer-safe signed token returned by /cli/exchange,
 * while the underlying Better Auth session is still stored server-side, so:
 * - It appears in the Manage Devices page
 * - Users can revoke CLI sessions from the UI
 * - The session can be scoped to an organization
 */
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
import { homedir } from 'os';
import { join } from 'path';
import pc from 'picocolors';
import prompts from 'prompts';
const CONFIG_DIR = join(homedir(), '.quickback');
const CREDENTIALS_FILE = join(CONFIG_DIR, 'credentials.json');
/**
 * Get stored CLI bearer token from credentials file.
 * Returns the bearer-safe signed CLI token from `quickback login`.
 * API keys (QUICKBACK_API_KEY env var) are handled separately in api-client.ts.
 */
export async function getStoredToken() {
    try {
        if (!existsSync(CREDENTIALS_FILE)) {
            return null;
        }
        const data = readFileSync(CREDENTIALS_FILE, 'utf-8');
        const credentials = JSON.parse(data);
        // Check if token is expired
        if (credentials.expiresAt) {
            const expiresAt = new Date(credentials.expiresAt);
            if (expiresAt < new Date()) {
                // Token expired, clear it
                await clearCredentials();
                return null;
            }
        }
        return credentials.token;
    }
    catch {
        return null;
    }
}
/**
 * Store auth credentials
 */
export async function storeCredentials(credentials) {
    // Ensure config directory exists
    if (!existsSync(CONFIG_DIR)) {
        mkdirSync(CONFIG_DIR, { recursive: true });
    }
    writeFileSync(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), 'utf-8');
}
/**
 * Clear stored credentials
 */
export async function clearCredentials() {
    if (existsSync(CREDENTIALS_FILE)) {
        unlinkSync(CREDENTIALS_FILE);
    }
}
/**
 * Get stored user info
 */
export async function getStoredUser() {
    try {
        if (!existsSync(CREDENTIALS_FILE)) {
            return null;
        }
        const data = readFileSync(CREDENTIALS_FILE, 'utf-8');
        const credentials = JSON.parse(data);
        return credentials.user || null;
    }
    catch {
        return null;
    }
}
/**
 * Check if user is logged in
 */
export async function isLoggedIn() {
    const token = await getStoredToken();
    return token !== null;
}
/**
 * Get stored organization info
 */
export async function getStoredOrganization() {
    try {
        if (!existsSync(CREDENTIALS_FILE)) {
            return null;
        }
        const data = readFileSync(CREDENTIALS_FILE, 'utf-8');
        const credentials = JSON.parse(data);
        return credentials.organization || null;
    }
    catch {
        return null;
    }
}
export async function ensureAuthForCompile(options) {
    const apiKey = process.env.QUICKBACK_API_KEY;
    if (apiKey) {
        return { status: 'authenticated', token: apiKey, via: 'api-key' };
    }
    const isLocal = options.apiUrl.includes('localhost') || options.apiUrl.includes('127.0.0.1');
    let token = await getStoredToken();
    if (token) {
        return { status: 'authenticated', token, via: 'session' };
    }
    if (isLocal) {
        return { status: 'local-no-auth' };
    }
    // No token + cloud compiler → prompt before failing with a 401.
    console.log(pc.yellow('\nAuthentication required.'));
    console.log(pc.gray('  Quickback needs to associate compiles with your account for'));
    console.log(pc.gray('  quota, audit logging, and Pro template access.'));
    if (options.reason) {
        console.log(pc.gray(`  ${options.reason}`));
    }
    console.log();
    const { action } = await prompts({
        type: 'select',
        name: 'action',
        message: 'How would you like to proceed?',
        choices: [
            { title: 'Sign in to an existing account', value: 'login' },
            { title: 'Create a new account (signup in browser)', value: 'signup' },
            { title: 'Cancel', value: 'cancel' },
        ],
        initial: 0,
    });
    if (action === 'cancel' || action === undefined) {
        return { status: 'cancelled' };
    }
    // Both choices go through the device flow. The browser lands on
    // `/cli/authorize`, which bounces unauthenticated users to /login,
    // which has a "Create one" link to /signup. Signup captures the
    // redirect and brings the user back to /cli/authorize once they've
    // accepted the terms.
    if (action === 'signup') {
        console.log(pc.gray('\nNo account yet? Click "Create one" on the login page that opens.'));
    }
    await options.loginFn();
    token = await getStoredToken();
    if (!token) {
        return { status: 'cancelled' };
    }
    console.log();
    return { status: 'authenticated', token, via: 'session' };
}
//# sourceMappingURL=auth.js.map