import { readFile } from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import spawn from 'cross-spawn';
import { readObjectRecord, readOptionalString } from '../../../../shared/utils.js';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore — plain-JS module
import { getProviderCredentials } from '../../../../services/provider-credentials.js';
export class ClaudeProviderAuth {
    /**
     * Checks whether the Claude Code CLI is available on this host.
     *
     * NOTE: `cross-spawn.sync` does NOT throw on ENOENT — it returns a result
     * object with `error` populated. The try/catch alone was always returning
     * true and every provider appeared "installed". We now require both
     * `!result.error` and a numeric exit status (0 for `--version`) before
     * trusting the install.
     */
    checkInstalled() {
        const cliPath = process.env.CLAUDE_CLI_PATH || 'claude';
        try {
            const result = spawn.sync(cliPath, ['--version'], { stdio: 'ignore', timeout: 5000 });
            return !result.error && result.status === 0;
        }
        catch {
            return false;
        }
    }
    /**
     * Returns Claude installation and credential status using Claude Code's auth priority.
     */
    async getStatus() {
        const installed = this.checkInstalled();
        if (!installed) {
            return {
                installed,
                provider: 'claude',
                authenticated: false,
                email: null,
                method: null,
                error: 'Claude Code CLI is not installed',
            };
        }
        const credentials = await this.checkCredentials();
        return {
            installed,
            provider: 'claude',
            authenticated: credentials.authenticated,
            email: credentials.authenticated ? credentials.email || 'Authenticated' : credentials.email,
            method: credentials.method,
            error: credentials.authenticated ? undefined : credentials.error || 'Not authenticated',
        };
    }
    /**
     * Reads Claude settings env values that the CLI can use even when the server process env is empty.
     */
    async loadSettingsEnv() {
        try {
            const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
            const content = await readFile(settingsPath, 'utf8');
            const settings = readObjectRecord(JSON.parse(content));
            return readObjectRecord(settings?.env) ?? {};
        }
        catch {
            return {};
        }
    }
    /**
     * Checks Claude credentials in the same priority order used by Claude Code.
     */
    async checkCredentials() {
        // Pixcode-UI-saved credentials win. Users who paste a key into our
        // Settings > Agents form expect authenticated status immediately,
        // regardless of env var timing.
        try {
            const creds = await getProviderCredentials('claude');
            if (creds?.apiKey) {
                const label = creds.baseUrl
                    ? `API Key · ${(() => { try {
                        return new URL(creds.baseUrl).host;
                    }
                    catch {
                        return creds.baseUrl;
                    } })()}`
                    : 'API Key Auth';
                return { authenticated: true, email: label, method: 'pixcode_store' };
            }
        }
        catch { /* fall through */ }
        if (process.env.ANTHROPIC_API_KEY?.trim()) {
            return { authenticated: true, email: 'API Key Auth', method: 'api_key' };
        }
        const settingsEnv = await this.loadSettingsEnv();
        if (readOptionalString(settingsEnv.ANTHROPIC_API_KEY)) {
            return { authenticated: true, email: 'API Key Auth', method: 'api_key' };
        }
        if (readOptionalString(settingsEnv.ANTHROPIC_AUTH_TOKEN)) {
            return { authenticated: true, email: 'Configured via settings.json', method: 'api_key' };
        }
        try {
            const credPath = path.join(os.homedir(), '.claude', '.credentials.json');
            const content = await readFile(credPath, 'utf8');
            const creds = readObjectRecord(JSON.parse(content)) ?? {};
            const oauth = readObjectRecord(creds.claudeAiOauth);
            const accessToken = readOptionalString(oauth?.accessToken);
            if (accessToken) {
                const expiresAt = typeof oauth?.expiresAt === 'number' ? oauth.expiresAt : undefined;
                const email = readOptionalString(creds.email) ?? readOptionalString(creds.user) ?? null;
                if (!expiresAt || Date.now() < expiresAt) {
                    return {
                        authenticated: true,
                        email,
                        method: 'credentials_file',
                    };
                }
                return {
                    authenticated: false,
                    email,
                    method: 'credentials_file',
                    error: 'OAuth token has expired. Please re-authenticate with claude login',
                };
            }
            return { authenticated: false, email: null, method: null };
        }
        catch {
            return { authenticated: false, email: null, method: null };
        }
    }
}
//# sourceMappingURL=claude-auth.provider.js.map