/**
 * Token Storage for OAuth 2.1 authentication
 * Provides implementations for storing OAuth tokens
 */
import { logger } from "../../utils/logger.js";
/**
 * In-memory token storage implementation
 * Suitable for development and single-session use
 * Tokens are lost when the process terminates
 */
export class InMemoryTokenStorage {
    tokens = new Map();
    async getTokens(serverId) {
        return this.tokens.get(serverId) ?? null;
    }
    async saveTokens(serverId, tokens) {
        this.tokens.set(serverId, tokens);
    }
    async deleteTokens(serverId) {
        this.tokens.delete(serverId);
    }
    async hasTokens(serverId) {
        return this.tokens.has(serverId);
    }
    async clearAll() {
        this.tokens.clear();
    }
    /**
     * Get the number of stored token sets
     */
    get size() {
        return this.tokens.size;
    }
    /**
     * Get all server IDs with stored tokens
     */
    getServerIds() {
        return Array.from(this.tokens.keys());
    }
}
/**
 * File-based token storage implementation
 * Persists tokens to disk for cross-session use
 */
export class FileTokenStorage {
    filePath;
    tokens = new Map();
    loaded = false;
    constructor(filePath) {
        this.filePath = filePath;
    }
    async loadTokens() {
        if (this.loaded) {
            return;
        }
        try {
            const fs = await import("fs/promises");
            const data = await fs.readFile(this.filePath, "utf-8");
            const parsed = JSON.parse(data);
            this.tokens = new Map(Object.entries(parsed));
            this.loaded = true;
        }
        catch (error) {
            // File doesn't exist or is invalid, start with empty tokens
            if (error instanceof Error &&
                "code" in error &&
                error.code !== "ENOENT") {
                logger.warn(`[FileTokenStorage] Error loading tokens: ${error.message}`);
            }
            this.tokens = new Map();
            this.loaded = true;
        }
    }
    async saveToFile() {
        try {
            const fs = await import("fs/promises");
            const path = await import("path");
            // Ensure directory exists
            const dir = path.dirname(this.filePath);
            await fs.mkdir(dir, { recursive: true });
            // Write tokens to file
            const data = Object.fromEntries(this.tokens.entries());
            await fs.writeFile(this.filePath, JSON.stringify(data, null, 2), "utf-8");
        }
        catch (error) {
            logger.error(`[FileTokenStorage] Error saving tokens: ${error instanceof Error ? error.message : String(error)}`);
            throw error;
        }
    }
    async getTokens(serverId) {
        await this.loadTokens();
        return this.tokens.get(serverId) ?? null;
    }
    async saveTokens(serverId, tokens) {
        await this.loadTokens();
        this.tokens.set(serverId, tokens);
        await this.saveToFile();
    }
    async deleteTokens(serverId) {
        await this.loadTokens();
        this.tokens.delete(serverId);
        await this.saveToFile();
    }
    async hasTokens(serverId) {
        await this.loadTokens();
        return this.tokens.has(serverId);
    }
    async clearAll() {
        this.tokens.clear();
        await this.saveToFile();
    }
}
/**
 * Check if tokens are expired or about to expire
 * @param tokens - OAuth tokens to check
 * @param bufferSeconds - Buffer time in seconds before expiration (default: 60)
 * @returns True if tokens are expired or will expire within buffer time
 */
export function isTokenExpired(tokens, bufferSeconds = 60) {
    if (!tokens.expiresAt) {
        return false; // No expiration set, assume valid
    }
    const bufferMs = bufferSeconds * 1000;
    const now = Date.now();
    return tokens.expiresAt - bufferMs <= now;
}
/**
 * Calculate token expiration timestamp from expires_in value
 * @param expiresIn - Token lifetime in seconds
 * @returns Expiration timestamp (Unix epoch in milliseconds)
 */
export function calculateExpiresAt(expiresIn) {
    return Date.now() + expiresIn * 1000;
}
