/**
 * olam auth — Manage the local auth container (the long-lived Linux container
 * that runs the same OAuth PKCE dance as the Cloudflare Worker and stores
 * Claude tokens in a named docker volume).
 *
 * Subcommands:
 *   olam auth up       — start the auth container (idempotent)
 *   olam auth down     — stop the auth container
 *   olam auth status   — show container state + account summary
 *   olam auth login    — run PKCE login flow (one-time per host)
 *   olam auth logout   — remove an account from the container
 *   olam auth refresh  — force-refresh a token
 */
import pc from 'picocolors';
import { AuthClient, AuthContainerController, runAuthPreflight, } from '@olam/core/src/auth/index.js';
import { printError, printHeader, printInfo, printSuccess, printWarning } from '../output.js';
import * as readline from 'node:readline/promises';
import { spawn } from 'node:child_process';
import { runAuthStatus } from './auth-status.js';
import { registerAuthUpgrade } from './auth-upgrade.js';
import { servicesUp, servicesDown, servicesStatus } from './services.js';
import { readConfig } from '../lib/config.js';
import { applyK8sAuthRefresh, resolveKubectlContext, } from '../lib/auth-refresh-kubernetes.js';
/**
 * Best-effort browser opener. Uses the host's native "open URL" command:
 * `open` on macOS, `xdg-open` on Linux, `start` on Windows. Silently
 * no-ops on failure — the URL is still printed for manual copy.
 */
function openBrowser(url) {
    const cmd = process.platform === 'darwin' ? 'open' :
        process.platform === 'win32' ? 'start' :
            'xdg-open';
    try {
        const child = spawn(cmd, [url], { detached: true, stdio: 'ignore' });
        child.unref();
    }
    catch {
        // Ignore — caller already printed the URL.
    }
}
async function promptLine(question) {
    const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
    try {
        const answer = await rl.question(question);
        return answer.trim();
    }
    finally {
        rl.close();
    }
}
export function registerAuth(program) {
    const auth = program
        .command('auth')
        .description('Manage the local Claude auth container');
    auth
        .command('up')
        .description('[deprecated] Start the auth container — use `olam services up` instead')
        .action(async () => {
        printWarning('`olam auth up` is deprecated. Use `olam services up` instead.');
        const result = await servicesUp();
        if (result.exitCode !== 0)
            process.exitCode = result.exitCode;
    });
    auth
        .command('down')
        .description('[deprecated] Stop the auth container — use `olam services down` instead')
        .action(() => {
        printWarning('`olam auth down` is deprecated. Use `olam services down` instead.');
        const result = servicesDown();
        if (result.exitCode !== 0)
            process.exitCode = result.exitCode;
    });
    auth
        .command('status')
        .description('[deprecated] Show container state — use `olam services status` instead')
        .action(() => {
        printWarning('`olam auth status` is deprecated. Use `olam services status` instead.');
        servicesStatus();
    });
    auth
        .command('list')
        .description('List all stored credentials with state, usage, and rate-limit status')
        .action(async () => {
        const client = new AuthClient();
        const status = await client.status();
        if (!status.reachable) {
            printError('Auth container is not reachable. Run `olam auth up` first.');
            process.exitCode = 1;
            return;
        }
        printHeader(`Credentials (${status.accounts.length})`);
        if (status.accounts.length === 0) {
            console.log(`  ${pc.dim('No credentials — run: olam auth login --label primary')}`);
            return;
        }
        const stateColor = (s) => {
            if (s === 'active')
                return pc.green('active');
            if (s === 'cooldown')
                return pc.yellow('cooldown');
            if (s === 'expired')
                return pc.red('expired');
            if (s === 'disabled')
                return pc.dim('disabled');
            return pc.dim(s ?? 'unknown');
        };
        for (const a of status.accounts) {
            const label = a.accountLabel ?? a.id;
            const reqs = a.usage?.requestCount5h ?? 0;
            const last429 = a.usage?.last429At
                ? `last429=${a.usage.last429At}`
                : 'last429=never';
            const reset = a.rateLimitResetsAt ? `resets=${a.rateLimitResetsAt}` : '';
            console.log(`  ${pc.bold(label.padEnd(18))} ${stateColor(a.state).padEnd(18)} ` +
                `${pc.dim(`req5h=${reqs}`)}  ${pc.dim(`exp=${a.expiresIn}`)} ${pc.dim(last429)} ${pc.yellow(reset)}`);
        }
    });
    auth
        .command('disable')
        .description('Take a credential out of rotation (manual cooldown)')
        .argument('<label>', 'Credential label or id')
        .action(async (label) => {
        const client = new AuthClient();
        try {
            await client.disableAccount(label);
            printSuccess(`Disabled: ${label}`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'failed to disable');
            process.exitCode = 1;
        }
    });
    auth
        .command('enable')
        .description('Re-enable a disabled credential')
        .argument('<label>', 'Credential label or id')
        .action(async (label) => {
        const client = new AuthClient();
        try {
            await client.enableAccount(label);
            printSuccess(`Enabled: ${label}`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'failed to enable');
            process.exitCode = 1;
        }
    });
    auth
        .command('remove')
        .description('Permanently remove a credential (purge tokens)')
        .argument('<label>', 'Credential label or id')
        .action(async (label) => {
        const client = new AuthClient();
        try {
            await client.deleteAccount(label);
            printSuccess(`Removed: ${label}`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'failed to remove');
            process.exitCode = 1;
        }
    });
    auth
        .command('login')
        .description('Run the OAuth PKCE flow to store a Claude account in the auth container')
        .option('--label <label>', 'Account label (e.g. primary, burner-1). Defaults to "primary" for the first account, "burner-N" thereafter.')
        .action(async (opts) => {
        const preflight = await runAuthPreflight({ autoStart: true });
        if (preflight.verdict !== 'ok' && preflight.verdict !== 'no-accounts') {
            printError(preflight.message);
            console.log(`  ${pc.dim(preflight.remedy)}`);
            process.exitCode = 1;
            return;
        }
        const client = new AuthClient();
        // Auto-pick a sensible label when the operator didn't supply one.
        // First credential → "primary"; subsequent → "burner-N" with N
        // chosen to dodge any existing label.
        let label = opts.label;
        if (!label) {
            try {
                const existing = await client.status();
                if (existing.accounts.length === 0) {
                    label = 'primary';
                }
                else {
                    const usedLabels = new Set(existing.accounts.map((a) => a.accountLabel ?? a.id));
                    let n = 1;
                    while (usedLabels.has(`burner-${n}`))
                        n += 1;
                    label = `burner-${n}`;
                }
            }
            catch {
                label = 'primary';
            }
        }
        let pending;
        try {
            pending = await client.startLogin(label);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'failed to start login');
            process.exitCode = 1;
            return;
        }
        printHeader('Claude OAuth — PKCE flow');
        console.log(`\n  ${pc.bold('1.')} Opening Claude in your default browser…`);
        console.log(`     ${pc.dim(pending.loginUrl)}`);
        openBrowser(pending.loginUrl);
        console.log(`\n  ${pc.bold('2.')} After approving, paste the authorization code from the redirect page.`);
        console.log(`     ${pc.dim('(Format: <code>#<state> or just <code>.)')}\n`);
        const raw = await promptLine(`${pc.dim('code:')} `);
        if (!raw) {
            printError('No code provided.');
            process.exitCode = 1;
            return;
        }
        const [codePart, statePart] = raw.includes('#') ? raw.split('#', 2) : [raw, pending.state];
        try {
            const result = await client.completeLogin(statePart, codePart);
            printSuccess(`Account stored: ${result.account} (${result.expiresIn})`);
            console.log(`\n${pc.dim('Next: olam create --name my-world')}`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'token exchange failed');
            process.exitCode = 1;
        }
    });
    auth
        .command('logout')
        .description('Remove an account from the auth container')
        .argument('<account>', 'Account id')
        .action(async (accountId) => {
        const client = new AuthClient();
        try {
            await client.deleteAccount(accountId);
            printSuccess(`Account removed: ${accountId}`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'failed to delete account');
            process.exitCode = 1;
        }
    });
    auth
        .command('refresh')
        .description('Force-refresh an account token (substrate-aware: updates kubernetes Secret on k8s substrate)')
        .argument('<account>', 'Account id')
        .action(async (accountId) => {
        const cfg = readConfig();
        const isK8s = cfg.host.substrate === 'kubernetes';
        // Kubernetes substrate: validate context before touching auth-service (SEC-NEW-003).
        if (isK8s) {
            const ctxResult = resolveKubectlContext();
            if (ctxResult.error) {
                printError(ctxResult.error);
                process.exitCode = 1;
                return;
            }
            if (ctxResult.deprecationWarning) {
                printWarning(ctxResult.deprecationWarning);
            }
        }
        const client = new AuthClient();
        try {
            const result = await client.refreshAccount(accountId);
            printSuccess(`Refreshed ${result.account} (${result.expiresIn})`);
        }
        catch (err) {
            printError(err instanceof Error ? err.message : 'refresh failed');
            process.exitCode = 1;
            return;
        }
        if (isK8s) {
            const ctxResult = resolveKubectlContext();
            if (ctxResult.context) {
                const code = await applyK8sAuthRefresh(ctxResult.context);
                if (code !== 0)
                    process.exitCode = code;
            }
        }
    });
    registerAuthUpgrade(auth);
}
//# sourceMappingURL=auth.js.map