"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getConfigManager = void 0;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const os_1 = __importDefault(require("os"));
const crypto_1 = require("crypto");
const logger_1 = require("../utils/logger");
const proxy_1 = require("../config/proxy");
const RequestAuthContext_1 = require("./RequestAuthContext");
const accessTokenRefresh_1 = require("./accessTokenRefresh");
const log = (0, logger_1.createLogger)('ConfigManager');
/**
 * ConfigManager handles local storage of Rivet configuration
 * Stores JWT tokens and user preferences in ~/.rivet/config.json
 */
class ConfigManager {
    configPath;
    config;
    constructor() {
        const homeDir = os_1.default.homedir();
        const rivetDir = path_1.default.join(homeDir, '.rivet');
        this.configPath = path_1.default.join(rivetDir, 'config.json');
        // Ensure .rivet directory exists
        if (!fs_1.default.existsSync(rivetDir)) {
            fs_1.default.mkdirSync(rivetDir, { recursive: true, mode: 0o700 });
            log.debug(`Created Rivet config directory: ${rivetDir}`);
        }
        // Load existing config or create empty one
        this.config = this.loadConfig();
    }
    /**
     * Load configuration from disk
     */
    loadConfig() {
        try {
            if (fs_1.default.existsSync(this.configPath)) {
                const data = fs_1.default.readFileSync(this.configPath, 'utf8');
                const config = JSON.parse(data);
                return config;
            }
        }
        catch (error) {
            log.warn('Failed to load config:', error);
        }
        return {};
    }
    /**
     * Save configuration to disk
     */
    saveConfig() {
        try {
            fs_1.default.writeFileSync(this.configPath, JSON.stringify(this.config, null, 2), {
                mode: 0o600,
            });
            log.debug(`Saved config to ${this.configPath}`);
        }
        catch (error) {
            log.error('Failed to save config:', error);
            throw new Error('Failed to save configuration');
        }
    }
    /**
     * Set authentication tokens, email, and (optionally) the Supabase user id.
     * `userId` is the canonical cross-surface identity — when omitted, an
     * existing stored value is preserved (callers that don't have it shouldn't
     * clobber it).
     */
    setAuth(token, email, refreshToken, userId) {
        this.config.authToken = token;
        this.config.refreshToken = refreshToken;
        this.config.email = email;
        if (userId) {
            this.config.userId = userId;
        }
        this.saveConfig();
        log.debug(`Saved auth tokens for ${email}`);
    }
    /**
     * Get authentication token
     */
    getAuthToken() {
        const requestContext = (0, RequestAuthContext_1.getRequestAuthContext)();
        if (requestContext) {
            return requestContext.token;
        }
        return this.config.authToken;
    }
    /**
     * Get refresh token
     */
    getRefreshToken() {
        const requestContext = (0, RequestAuthContext_1.getRequestAuthContext)();
        if (requestContext) {
            return requestContext.refreshToken;
        }
        return this.config.refreshToken;
    }
    /**
     * Get user email
     */
    getEmail() {
        const requestContext = (0, RequestAuthContext_1.getRequestAuthContext)();
        if (requestContext) {
            return requestContext.email;
        }
        return this.config.email;
    }
    /**
     * Get the canonical Supabase user id. Falls back to the request-scoped
     * context, then to the stored value, and finally backfills it by decoding
     * the `sub` claim of the stored access token (no verification — we already
     * trust the token locally). Backfill persists so we only decode once.
     */
    getUserId() {
        const requestContext = (0, RequestAuthContext_1.getRequestAuthContext)();
        if (requestContext) {
            return requestContext.userId;
        }
        if (this.config.userId) {
            return this.config.userId;
        }
        if (this.config.authToken) {
            const sub = (0, accessTokenRefresh_1.getJwtSub)(this.config.authToken);
            if (sub) {
                this.config.userId = sub;
                this.saveConfig();
                return sub;
            }
        }
        return undefined;
    }
    /**
     * Get the user's display name (e.g. "Sam Gorman"), decoded from the access
     * token's `user_metadata`. Not all tokens carry it (e.g. email-only logins),
     * so callers should fall back to the email for initials. Decoded on demand —
     * the token is the source of truth, so nothing is persisted here.
     */
    getDisplayName() {
        const token = this.getAuthToken();
        if (!token) {
            return undefined;
        }
        return (0, accessTokenRefresh_1.getJwtDisplayName)(token) ?? undefined;
    }
    /**
     * Check if user is authenticated
     */
    isAuthenticated() {
        return !!this.getAuthToken();
    }
    /**
     * Clear authentication (logout)
     */
    clearAuth() {
        this.config.authToken = undefined;
        this.config.refreshToken = undefined;
        this.config.email = undefined;
        this.config.userId = undefined;
        this.config.telemetryIdentifiedEmail = undefined;
        this.config.telemetryIdentifiedUserId = undefined;
        this.saveConfig();
        log.debug('Cleared authentication');
    }
    /**
     * Set proxy URL
     */
    setProxyUrl(url) {
        this.config.proxyUrl = url;
        this.saveConfig();
        log.debug(`Set proxy URL: ${url}`);
    }
    /**
     * Get or create a persistent anonymous ID for telemetry.
     * Generated once on first call and stored in config.json.
     */
    getAnonymousId() {
        if (!this.config.anonymousId) {
            this.config.anonymousId = `anon-${(0, crypto_1.randomUUID)()}`;
            this.saveConfig();
            log.debug(`Generated anonymous ID: ${this.config.anonymousId}`);
        }
        return this.config.anonymousId;
    }
    /**
     * Email last identified to PostHog. Used to suppress redundant alias/identify
     * calls on subsequent process starts — posthog-node has no built-in dedup,
     * so each call would emit a fresh $create_alias event.
     */
    getTelemetryIdentifiedEmail() {
        return this.config.telemetryIdentifiedEmail;
    }
    setTelemetryIdentifiedEmail(email) {
        this.config.telemetryIdentifiedEmail = email;
        this.saveConfig();
    }
    /**
     * Supabase user id last identified to PostHog. Used to suppress redundant
     * alias/identify calls once analytics identity is keyed on user id.
     */
    getTelemetryIdentifiedUserId() {
        return this.config.telemetryIdentifiedUserId;
    }
    setTelemetryIdentifiedUserId(userId) {
        this.config.telemetryIdentifiedUserId = userId;
        this.saveConfig();
    }
    /**
     * Get proxy URL
     */
    getProxyUrl() {
        return this.config.proxyUrl || proxy_1.PROXY_URL;
    }
    /**
     * Get full config
     */
    getConfig() {
        return { ...this.config };
    }
    /**
     * Get config file path for debugging
     */
    getConfigPath() {
        return this.configPath;
    }
}
// Singleton instance
let configManager = null;
const getConfigManager = () => {
    if (!configManager) {
        configManager = new ConfigManager();
    }
    return configManager;
};
exports.getConfigManager = getConfigManager;
//# sourceMappingURL=ConfigManager.js.map