// src/lib/auth/providers/firebase.ts
import { BaseAuthProvider } from "./BaseAuthProvider.js";
import { AuthError } from "../errors.js";
import { logger } from "../../utils/logger.js";
import { createProxyFetch } from "../../proxy/proxyFetch.js";
import * as jose from "jose";
/**
 * Firebase Authentication Provider
 *
 * Supports Firebase ID token validation using Google's public keys.
 * Can validate tokens locally or via Firebase REST API.
 *
 * Features:
 * - JWT validation using Google's public keys
 * - Token verification via Firebase REST API
 * - Custom claims extraction for roles/permissions
 *
 * @example
 * ```typescript
 * const firebase = new FirebaseAuthProvider({
 *   type: "firebase",
 *   projectId: "your-project-id"
 * });
 *
 * const result = await firebase.authenticateToken(idToken);
 * if (result.valid) {
 *   console.log("Authenticated user:", result.user);
 * }
 * ```
 */
export class FirebaseAuthProvider extends BaseAuthProvider {
    type = "firebase";
    projectId;
    apiKey;
    serviceAccount;
    jwks = null;
    constructor(config) {
        super(config);
        if (!config.projectId) {
            throw AuthError.create("CONFIGURATION_ERROR", "Firebase projectId is required", { details: { missingFields: ["projectId"] } });
        }
        this.projectId = config.projectId;
        this.apiKey = config.apiKey;
        this.serviceAccount = config.serviceAccount;
    }
    /**
     * Initialize JWKS for Firebase token verification
     */
    async initialize() {
        // Firebase uses Google's secure token service public keys
        const jwksUrl = new URL("https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com");
        this.jwks = jose.createRemoteJWKSet(jwksUrl);
        logger.debug(`Firebase provider initialized for project: ${this.projectId}`);
    }
    /**
     * Validate Firebase ID token
     */
    async authenticateToken(token, _context) {
        if (!this.jwks) {
            await this.initialize();
        }
        try {
            const jwks = this.jwks;
            if (!jwks) {
                throw AuthError.create("PROVIDER_INIT_FAILED", "Firebase JWKS was not initialized", { details: { provider: "firebase" } });
            }
            // Verify the token using Google's public keys
            const { payload } = await jose.jwtVerify(token, jwks, {
                issuer: `https://securetoken.google.com/${this.projectId}`,
                audience: this.projectId,
            });
            // Extract user info from Firebase token claims
            const user = this.payloadToUser(payload);
            return {
                valid: true,
                payload: payload,
                user,
                expiresAt: payload.exp ? new Date(payload.exp * 1000) : undefined,
                tokenType: "jwt",
            };
        }
        catch (error) {
            // If local validation fails and API key is available, try REST API
            if (this.apiKey) {
                return this.validateViaApi(token);
            }
            return {
                valid: false,
                error: error instanceof Error ? error.message : String(error),
            };
        }
    }
    /**
     * Validate token via Firebase REST API
     */
    async validateViaApi(token) {
        try {
            const proxyFetch = createProxyFetch();
            const response = await proxyFetch(`https://identitytoolkit.googleapis.com/v1/accounts:lookup?key=${this.apiKey}`, {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                },
                body: JSON.stringify({ idToken: token }),
                signal: AbortSignal.timeout(5000),
            });
            if (!response.ok) {
                const error = (await response.json());
                return {
                    valid: false,
                    error: error.error?.message || `Firebase API returned ${response.status}`,
                };
            }
            const data = (await response.json());
            const users = data.users || [];
            if (users.length === 0) {
                return {
                    valid: false,
                    error: "User not found",
                };
            }
            const userData = users[0];
            const user = this.firebaseUserToAuthUser(userData);
            return {
                valid: true,
                payload: userData,
                user,
                tokenType: "jwt",
            };
        }
        catch (error) {
            return {
                valid: false,
                error: error instanceof Error ? error.message : String(error),
            };
        }
    }
    /**
     * Convert JWT payload to AuthUser
     */
    payloadToUser(payload) {
        // Extract custom claims
        const customClaims = payload;
        return {
            id: payload.sub,
            email: payload.email,
            name: payload.name,
            picture: payload.picture,
            emailVerified: payload.email_verified,
            roles: customClaims.roles || [],
            permissions: customClaims.permissions || [],
            metadata: {
                firebase: {
                    sign_in_provider: payload.firebase?.sign_in_provider ||
                        "unknown",
                    identities: payload.firebase?.identities,
                },
            },
        };
    }
    /**
     * Convert Firebase user data to AuthUser
     */
    firebaseUserToAuthUser(userData) {
        let customAttributes = {};
        if (userData.customAttributes) {
            try {
                customAttributes = JSON.parse(userData.customAttributes);
            }
            catch {
                logger.warn("Failed to parse Firebase customAttributes, treating as empty");
            }
        }
        return {
            id: userData.localId,
            email: userData.email,
            name: userData.displayName,
            picture: userData.photoUrl,
            emailVerified: userData.emailVerified,
            roles: customAttributes.roles || [],
            permissions: customAttributes.permissions || [],
            createdAt: userData.createdAt
                ? new Date(parseInt(userData.createdAt))
                : undefined,
            lastLoginAt: userData.lastLoginAt
                ? new Date(parseInt(userData.lastLoginAt))
                : undefined,
            metadata: {
                providerUserInfo: userData.providerUserInfo,
            },
        };
    }
    /**
     * Get user by ID via Firebase REST API
     * Requires API key
     */
    async getUser(_userId) {
        if (!this.apiKey) {
            logger.warn("Firebase API key required for user lookup");
            return null;
        }
        // Firebase REST API doesn't support direct user lookup by UID
        // This would require Admin SDK or custom backend
        logger.warn("Direct user lookup by ID requires Firebase Admin SDK which is not supported in browser/edge environments");
        return null;
    }
    /**
     * Health check
     */
    async healthCheck() {
        try {
            // Check if we can fetch the JWKS
            const proxyFetch = createProxyFetch();
            const response = await proxyFetch("https://www.googleapis.com/service_accounts/v1/jwk/securetoken@system.gserviceaccount.com", { signal: AbortSignal.timeout(5000) });
            return {
                healthy: response.ok,
                providerConnected: response.ok,
                sessionStorageHealthy: true,
            };
        }
        catch (error) {
            return {
                healthy: false,
                providerConnected: false,
                sessionStorageHealthy: true,
                error: error instanceof Error ? error.message : String(error),
            };
        }
    }
}
//# sourceMappingURL=firebase.js.map