import puppeteer from 'puppeteer-core';
import { ServiceBubble } from '../../../types/service-bubble-class.js';
import { CredentialType, BROWSER_SESSION_PROVIDERS, decodeCredentialPayload, } from '@bubblelab/shared-schemas';
import { BrowserBaseParamsSchema, BrowserBaseResultSchema, BrowserSessionDataSchema, } from './browserbase.schema.js';
/**
 * BrowserBase Service Bubble
 *
 * Provides browser automation capabilities using BrowserBase cloud browsers.
 * Supports session management, navigation, clicking, typing, JavaScript
 * execution, content extraction, screenshots, and cookie management.
 *
 * Features:
 * - Cloud-based browser sessions (BrowserBase)
 * - Session persistence via context IDs
 * - Cookie injection for authenticated sessions
 * - Full page automation (click, type, evaluate)
 * - Screenshot and content extraction
 * - Stealth mode for anti-bot avoidance
 * - Automatic CAPTCHA solving
 * - Proxy support (built-in and custom)
 *
 * Stealth Mode:
 * - Basic Stealth: Automatic fingerprint randomization
 * - Advanced Stealth: Custom Chromium for better anti-bot avoidance (Scale Plan)
 * - CAPTCHA Solving: Automatic detection and solving (enabled by default)
 *
 * Proxy Options:
 * - Built-in proxies: Residential proxies with geolocation support
 * - Custom proxies: Use your own HTTP/HTTPS proxies
 * - Routing rules: Route different domains through different proxies
 *
 * Use cases:
 * - Automated shopping workflows (Amazon, etc.)
 * - Web scraping with authentication
 * - Form automation and submission
 * - Browser-based testing
 *
 * Security Features:
 * - Sessions are isolated in BrowserBase cloud
 * - Credentials are handled securely
 * - Sessions are properly closed and cleaned up
 */
export class BrowserBaseBubble extends ServiceBubble {
    static type = 'service';
    static service = 'browserbase';
    static authType = 'apikey';
    static bubbleName = 'browserbase';
    static schema = BrowserBaseParamsSchema;
    static resultSchema = BrowserBaseResultSchema;
    static shortDescription = 'Browser automation service using BrowserBase cloud browsers';
    static longDescription = `
    BrowserBase service integration for cloud-based browser automation.

    Features:
    - Cloud-based browser sessions
    - Session persistence via context IDs
    - Cookie injection for authenticated sessions
    - Full page automation (click, type, evaluate)
    - Screenshot and content extraction
    - Stealth mode for anti-bot avoidance
    - Automatic CAPTCHA solving
    - Built-in and custom proxy support

    Stealth Mode Options:
    - Basic Stealth: Automatic browser fingerprint randomization (default)
    - Advanced Stealth: Custom Chromium browser for better anti-bot avoidance (Scale Plan only)
    - CAPTCHA Solving: Automatic detection and solving (enabled by default, can be disabled)
    - Custom CAPTCHA selectors: For non-standard CAPTCHA providers

    Proxy Options:
    - Built-in proxies: Set proxies=true for residential proxies with geolocation
    - Geolocation: Specify city, state (US only), and country for proxy location
    - Custom proxies: Use your own HTTP/HTTPS proxies with authentication
    - Routing rules: Route different domains through different proxies using domainPattern

    Use cases:
    - Automated shopping workflows (Amazon, etc.)
    - Web scraping with authentication
    - Form automation and submission
    - Browser-based testing

    Security Features:
    - Sessions are isolated in BrowserBase cloud
    - Credentials are handled securely
    - Sessions are properly closed and cleaned up
  `;
    static alias = 'browser';
    // Static session store shared across instances
    static activeSessions = new Map();
    constructor(params = {
        operation: 'start_session',
    }, context, instanceId) {
        super(params, context, instanceId);
    }
    /**
     * Get BrowserBase configuration from environment
     */
    getConfig() {
        const apiKey = process.env.BROWSERBASE_API_KEY;
        const projectId = process.env.BROWSERBASE_PROJECT_ID;
        if (!apiKey || !projectId) {
            return null;
        }
        return {
            apiKey,
            projectId,
            baseUrl: 'https://api.browserbase.com/v1',
        };
    }
    /**
     * Make an API request to BrowserBase
     */
    async browserbaseApi(endpoint, method = 'GET', body) {
        const config = this.getConfig();
        if (!config) {
            throw new Error('BrowserBase not configured');
        }
        const url = `${config.baseUrl}${endpoint}`;
        const headers = {
            'x-bb-api-key': config.apiKey,
            'Content-Type': 'application/json',
        };
        const requestInit = { method, headers };
        if (body) {
            requestInit.body = JSON.stringify(body);
        }
        const response = await fetch(url, requestInit);
        if (!response.ok) {
            const errorText = await response.text();
            throw new Error(`BrowserBase API error: ${response.status} ${response.statusText} - ${errorText}`);
        }
        return (await response.json());
    }
    /**
     * Parse browser session credential data (cookies + contextId)
     * Credential is base64-encoded JSON to avoid escaping issues
     */
    parseBrowserSessionCredential(credentialValue) {
        try {
            const parsed = decodeCredentialPayload(credentialValue);
            const validated = BrowserSessionDataSchema.safeParse(parsed);
            if (validated.success) {
                return validated.data;
            }
            console.error('[BrowserBaseBubble] Invalid credential format:', validated.error);
            return null;
        }
        catch (error) {
            console.error('[BrowserBaseBubble] Failed to parse credential:', error);
            return null;
        }
    }
    /**
     * Normalize proxy server to valid URL (BrowserBase requires http/https)
     */
    normalizeProxyServer(server) {
        const s = server.trim();
        return /^https?:\/\//i.test(s) ? s : `http://${s}`;
    }
    /**
     * Build proxy configuration for BrowserBase API
     * Converts our schema format to the API format
     */
    buildProxyConfig(proxies) {
        // Simple boolean proxy (use built-in proxies)
        if (proxies === true) {
            return true;
        }
        // Array of proxy configurations
        return proxies.map((proxy) => {
            if (proxy.type === 'browserbase') {
                const config = { type: 'browserbase' };
                if (proxy.geolocation) {
                    config.geolocation = {
                        ...(proxy.geolocation.city && { city: proxy.geolocation.city }),
                        ...(proxy.geolocation.state && { state: proxy.geolocation.state }),
                        country: proxy.geolocation.country,
                    };
                }
                if (proxy.domainPattern) {
                    config.domainPattern = proxy.domainPattern;
                }
                return config;
            }
            else {
                // External proxy
                const config = {
                    type: 'external',
                    server: this.normalizeProxyServer(proxy.server),
                };
                if (proxy.username) {
                    config.username = proxy.username;
                }
                if (proxy.password) {
                    config.password = proxy.password;
                }
                if (proxy.domainPattern) {
                    config.domainPattern = proxy.domainPattern;
                }
                return config;
            }
        });
    }
    async testCredential() {
        const config = this.getConfig();
        if (!config) {
            return false;
        }
        // Test by listing projects (simple API call) — let errors propagate
        await this.browserbaseApi('/projects');
        return true;
    }
    async performAction(context) {
        void context;
        const { operation } = this.params;
        const parsedParams = this.params;
        try {
            const result = await (async () => {
                switch (operation) {
                    case 'start_session':
                        return await this.startSession(parsedParams);
                    case 'navigate':
                        return await this.navigate(parsedParams);
                    case 'click':
                        return await this.click(parsedParams);
                    case 'type':
                        return await this.typeText(parsedParams);
                    case 'select':
                        return await this.selectOption(parsedParams);
                    case 'evaluate':
                        return await this.evaluate(parsedParams);
                    case 'get_content':
                        return await this.getContent(parsedParams);
                    case 'screenshot':
                        return await this.screenshot(parsedParams);
                    case 'wait':
                        return await this.waitFor(parsedParams);
                    case 'get_cookies':
                        return await this.getCookies(parsedParams);
                    case 'end_session':
                        return await this.endSession(parsedParams);
                    default:
                        throw new Error(`Unsupported operation: ${operation}`);
                }
            })();
            return result;
        }
        catch (error) {
            return {
                operation,
                success: false,
                error: error instanceof Error ? error.message : 'Unknown error occurred',
            };
        }
    }
    /**
     * Start a new browser session
     */
    async startSession(params) {
        const config = this.getConfig();
        if (!config) {
            return {
                operation: 'start_session',
                success: false,
                error: 'BrowserBase not configured - set BROWSERBASE_API_KEY and BROWSERBASE_PROJECT_ID',
            };
        }
        let contextId = params.context_id;
        let cookiesToInject = params.cookies;
        const hasExistingContext = !!contextId;
        // Try to get contextId from credentials if not provided
        if (!contextId && params.credentials) {
            const amazonCred = params.credentials[CredentialType.AMAZON_CRED];
            if (amazonCred) {
                const sessionData = this.parseBrowserSessionCredential(amazonCred);
                if (sessionData) {
                    contextId = sessionData.contextId;
                    // Only use cookies as fallback if no contextId from credential
                    if (!contextId && sessionData.cookies) {
                        cookiesToInject = sessionData.cookies;
                    }
                    if (contextId) {
                        console.log(`[BrowserBaseBubble] Using contextId from AMAZON_CRED: ${contextId}`);
                    }
                }
            }
        }
        const contextFromCredential = !hasExistingContext && !!contextId;
        // Create new context if none provided
        if (!contextId) {
            const contextResponse = await this.browserbaseApi('/contexts', 'POST', { projectId: config.projectId });
            contextId = contextResponse.id;
            console.log(`[BrowserBaseBubble] Created new context: ${contextId}`);
        }
        // Build browser settings with context, stealth, and CAPTCHA options
        const browserSettings = {
            context: { id: contextId, persist: true },
        };
        // Apply stealth mode configuration
        if (params.stealth) {
            if (params.stealth.advancedStealth !== undefined) {
                browserSettings.advancedStealth = params.stealth.advancedStealth;
            }
            if (params.stealth.solveCaptchas !== undefined) {
                browserSettings.solveCaptchas = params.stealth.solveCaptchas;
            }
            if (params.stealth.captchaImageSelector) {
                browserSettings.captchaImageSelector =
                    params.stealth.captchaImageSelector;
            }
            if (params.stealth.captchaInputSelector) {
                browserSettings.captchaInputSelector =
                    params.stealth.captchaInputSelector;
            }
        }
        // Build session creation request body
        const sessionRequestBody = {
            projectId: config.projectId,
            browserSettings,
        };
        // Apply session timeout (BrowserBase: top-level, 60-21600 seconds)
        if (params.timeout_seconds !== undefined) {
            sessionRequestBody.timeout = params.timeout_seconds;
        }
        // Apply proxy configuration: params.proxies > embedded proxy in session credential
        if (params.proxies) {
            sessionRequestBody.proxies = this.buildProxyConfig(params.proxies);
        }
        else if (params.credentials) {
            // Check embedded proxy in session credentials (browser session types from BROWSER_SESSION_PROVIDERS)
            const sessionCredTypes = Object.keys(BROWSER_SESSION_PROVIDERS.browserbase.credentialTypes);
            for (const credType of sessionCredTypes) {
                const credValue = params.credentials[credType];
                if (credValue) {
                    const sessionData = this.parseBrowserSessionCredential(credValue);
                    if (sessionData?.proxy?.server) {
                        const proxyConfig = {
                            type: 'external',
                            server: this.normalizeProxyServer(sessionData.proxy.server),
                        };
                        if (sessionData.proxy.username) {
                            proxyConfig.username = sessionData.proxy.username;
                        }
                        if (sessionData.proxy.password) {
                            proxyConfig.password = sessionData.proxy.password;
                        }
                        sessionRequestBody.proxies = [proxyConfig];
                        console.log(`[BrowserBaseBubble] Using embedded proxy from ${credType}`);
                        break;
                    }
                }
            }
        }
        // Log proxy config when present (helps verify proxies are properly received)
        if (sessionRequestBody.proxies) {
            const proxiesForLog = sessionRequestBody.proxies === true
                ? 'built-in (proxies: true)'
                : Array.isArray(sessionRequestBody.proxies)
                    ? sessionRequestBody.proxies
                        .map((p) => p.type === 'browserbase'
                        ? 'browserbase'
                        : `external ${p.server ?? '?'}`)
                        .join(', ')
                    : String(sessionRequestBody.proxies);
            console.log(`[BrowserBaseBubble] Proxies received for session: ${proxiesForLog}`);
        }
        // Create session with context, stealth, and proxy settings
        const sessionResponse = await this.browserbaseApi('/sessions', 'POST', sessionRequestBody);
        const sessionId = sessionResponse.id;
        const connectUrl = sessionResponse.connectUrl;
        console.log(`[BrowserBaseBubble] Session created: ${sessionId}`);
        // Connect via Puppeteer
        const browser = await puppeteer.connect({
            browserWSEndpoint: connectUrl,
            defaultViewport: {
                width: params.viewport_width || 1280,
                height: params.viewport_height || 900,
            },
        });
        const pages = await browser.pages();
        const page = pages[0] || (await browser.newPage());
        // Override browser dialogs (alert, confirm, prompt, print) to prevent them
        // from blocking automation. Uses CDP to auto-inject on every new document.
        try {
            const cdpClient = await page.createCDPSession();
            await cdpClient.send('Page.addScriptToEvaluateOnNewDocument', {
                source: `
          window.alert = (msg) => console.log('Suppressed alert:', msg);
          window.confirm = (msg) => { console.log('Suppressed confirm:', msg); return true; };
          window.prompt = (msg, def) => { console.log('Suppressed prompt:', msg); return def || ''; };
          window.print = () => console.log('Suppressed print dialog');
        `,
            });
            // Also inject into current page immediately
            await page.evaluate(() => {
                /* eslint-disable @typescript-eslint/no-explicit-any */
                const w = globalThis;
                w.alert = (msg) => console.log('Suppressed alert:', msg);
                w.confirm = (msg) => {
                    console.log('Suppressed confirm:', msg);
                    return true;
                };
                w.prompt = (msg, def) => {
                    console.log('Suppressed prompt:', msg);
                    return def || '';
                };
                w.print = () => console.log('Suppressed print dialog');
            });
        }
        catch (e) {
            console.warn('[BrowserBaseBubble] Failed to inject dialog overrides:', e);
        }
        // Log exit IP when using proxies (helps verify proxy routing)
        if (sessionRequestBody.proxies) {
            try {
                const ip = await page.evaluate(async () => {
                    const res = await fetch('https://api.ipify.org?format=json');
                    const json = await res.json();
                    return json.ip;
                });
                console.log(`[BrowserBaseBubble] Session ${sessionId} exit IP: ${ip}`);
            }
            catch (e) {
                console.warn('[BrowserBaseBubble] Failed to fetch exit IP for session:', e);
            }
        }
        // Only inject cookies if we created a new context (no existing contextId from param or credential)
        // When contextId exists, BrowserBase context handles cookie persistence automatically
        if (!hasExistingContext &&
            !contextFromCredential &&
            cookiesToInject &&
            cookiesToInject.length > 0) {
            const client = await page.createCDPSession();
            for (const cookie of cookiesToInject) {
                await client.send('Network.setCookie', {
                    name: cookie.name,
                    value: cookie.value,
                    domain: cookie.domain,
                    path: cookie.path,
                    expires: cookie.expires,
                    httpOnly: cookie.httpOnly,
                    secure: cookie.secure,
                });
            }
            console.log(`[BrowserBaseBubble] Injected ${cookiesToInject.length} cookies (no context)`);
        }
        // Get debug URL
        const debugResponse = await this.browserbaseApi(`/sessions/${sessionId}/debug`);
        // Store session with start time for cost tracking
        BrowserBaseBubble.activeSessions.set(sessionId, {
            sessionId,
            contextId,
            browser,
            page,
            connectUrl,
            startTime: Date.now(),
        });
        // Emit browser session start event for live viewing in UI
        if (this.context?.logger) {
            this.context.logger.logBrowserSessionStart(sessionId, debugResponse.debuggerFullscreenUrl, this.context.variableId);
        }
        return {
            operation: 'start_session',
            success: true,
            session_id: sessionId,
            context_id: contextId,
            debug_url: debugResponse.debuggerFullscreenUrl,
            error: '',
        };
    }
    /**
     * Navigate to a URL
     */
    async navigate(params) {
        const session = BrowserBaseBubble.activeSessions.get(params.session_id);
        if (!session) {
            return {
                operation: 'navigate',
                success: false,
                error: 'Session not found. Call start_session first.',
            };
        }
        await session.page.goto(params.url, {
            waitUntil: params.wait_until,
            timeout: params.timeout,
        });
        return {
            operation: 'navigate',
            success: true,
            url: session.page.url(),
            error: '',
        };
    }
    /**
     * Click an element
     */
    async click(params) {
        const session = BrowserBaseBubble.activeSessions.get(params.session_id);
        if (!session) {
            return {
                operation: 'click',
                success: false,
                error: 'Session not found. Call start_session first.',
            };
        }
        await session.page.waitForSelector(params.selector, {
            timeout: params.timeout,
        });
        if (params.wait_for_navigation) {
            await Promise.all([
                session.page.waitForNavigation({
                    waitUntil: 'domcontentloaded',
                    timeout: params.timeout,
                }),
                session.page.click(params.selector),
            ]);
        }
        else {
            await session.page.click(params.selector);
        }
        return {
            operation: 'click',
            success: true,
            error: '',
        };
    }
    /**
     * Type text into an element
     */
    async typeText(params) {
        const session = BrowserBaseBubble.activeSessions.get(params.session_id);
        if (!session) {
            return {
                operation: 'type',
                success: false,
                error: 'Session not found. Call start_session first.',
            };
        }
        await session.page.waitForSelector(params.selector);
        if (params.clear_first) {
            await session.page.click(params.selector, { clickCount: 3 });
            await session.page.keyboard.press('Backspace');
        }
        await session.page.type(params.selector, params.text, {
            delay: params.delay,
        });
        return {
            operation: 'type',
            success: true,
            error: '',
        };
    }
    /**
     * Select an option in a <select> element using Puppeteer's page.select()
     */
    async selectOption(params) {
        const session = BrowserBaseBubble.activeSessions.get(params.session_id);
        if (!session) {
            return {
                operation: 'select',
                success: false,
                error: 'Session not found. Call start_session first.',
            };
        }
        await session.page.waitForSelector(params.selector, {
            timeout: params.timeout,
        });
        // Use page.select() for native Puppeteer select handling
        await session.page.select(params.selector, params.value);
        // Also dispatch events via the native prototype setter to ensure
        // React-controlled selects pick up the change. React uses an internal
        // _valueTracker that must be reset before dispatching, otherwise React
        // sees no change and skips the onChange handler.
        const escapedSelector = params.selector.replace(/'/g, "\\'");
        const escapedValue = params.value.replace(/'/g, "\\'");
        await session.page.evaluate(`(() => {
      const el = document.querySelector('${escapedSelector}');
      if (el) {
        // Reset React's internal _valueTracker
        const tracker = el._valueTracker;
        if (tracker) {
          tracker.setValue('');
        }
        const nativeSelectSetter = Object.getOwnPropertyDescriptor(
          window.HTMLSelectElement.prototype, 'value'
        );
        if (nativeSelectSetter && nativeSelectSetter.set) {
          nativeSelectSetter.set.call(el, '${escapedValue}');
        }
        el.dispatchEvent(new Event('input', { bubbles: true }));
        el.dispatchEvent(new Event('change', { bubbles: true }));
      }
    })()`);
        return {
            operation: 'select',
            success: true,
            error: '',
        };
    }
    /**
     * Execute JavaScript in page context
     */
    async evaluate(params) {
        const session = BrowserBaseBubble.activeSessions.get(params.session_id);
        if (!session) {
            return {
                operation: 'evaluate',
                success: false,
                error: 'Session not found. Call start_session first.',
            };
        }
        // Wrap script in an async function for safety
        const result = await session.page.evaluate(params.script);
        return {
            operation: 'evaluate',
            success: true,
            result,
            error: '',
        };
    }
    /**
     * Get page or element content
     */
    async getContent(params) {
        const session = BrowserBaseBubble.activeSessions.get(params.session_id);
        if (!session) {
            return {
                operation: 'get_content',
                success: false,
                error: 'Session not found. Call start_session first.',
            };
        }
        let content;
        const selector = params.selector || 'body';
        if (params.content_type === 'html') {
            content = await session.page.$eval(selector, (el) => el.innerHTML);
        }
        else if (params.content_type === 'outer_html') {
            content = await session.page.$eval(selector, (el) => el.outerHTML);
        }
        else {
            content = await session.page.$eval(selector, (el) => el.textContent || '');
        }
        return {
            operation: 'get_content',
            success: true,
            content,
            error: '',
        };
    }
    /**
     * Take a screenshot
     */
    async screenshot(params) {
        const session = BrowserBaseBubble.activeSessions.get(params.session_id);
        if (!session) {
            return {
                operation: 'screenshot',
                success: false,
                error: 'Session not found. Call start_session first.',
            };
        }
        const options = {
            encoding: 'base64',
            fullPage: params.full_page,
            type: params.format || 'png',
        };
        if (params.quality &&
            (params.format === 'jpeg' || params.format === 'webp')) {
            options.quality = params.quality;
        }
        let data;
        if (params.selector) {
            const element = await session.page.$(params.selector);
            if (!element) {
                return {
                    operation: 'screenshot',
                    success: false,
                    error: `Element not found: ${params.selector}`,
                };
            }
            data = (await element.screenshot(options));
        }
        else {
            data = (await session.page.screenshot(options));
        }
        return {
            operation: 'screenshot',
            success: true,
            data,
            format: params.format || 'png',
            error: '',
        };
    }
    /**
     * Wait for a condition
     */
    async waitFor(params) {
        const session = BrowserBaseBubble.activeSessions.get(params.session_id);
        if (!session) {
            return {
                operation: 'wait',
                success: false,
                error: 'Session not found. Call start_session first.',
            };
        }
        switch (params.wait_type) {
            case 'selector':
                if (!params.selector) {
                    return {
                        operation: 'wait',
                        success: false,
                        error: 'Selector required for selector wait type',
                    };
                }
                await session.page.waitForSelector(params.selector, {
                    timeout: params.timeout,
                });
                break;
            case 'timeout':
                await new Promise((resolve) => setTimeout(resolve, params.timeout));
                break;
            case 'navigation':
                await session.page.waitForNavigation({
                    timeout: params.timeout,
                    waitUntil: 'domcontentloaded',
                });
                break;
        }
        return {
            operation: 'wait',
            success: true,
            error: '',
        };
    }
    /**
     * Get cookies from the browser
     */
    async getCookies(params) {
        const session = BrowserBaseBubble.activeSessions.get(params.session_id);
        if (!session) {
            return {
                operation: 'get_cookies',
                success: false,
                error: 'Session not found. Call start_session first.',
            };
        }
        const client = await session.page.createCDPSession();
        const { cookies } = (await client.send('Network.getAllCookies'));
        let filteredCookies = cookies;
        if (params.domain_filter) {
            filteredCookies = cookies.filter((c) => c.domain.includes(params.domain_filter));
        }
        return {
            operation: 'get_cookies',
            success: true,
            cookies: filteredCookies,
            error: '',
        };
    }
    /**
     * End a browser session
     */
    async endSession(params) {
        const session = BrowserBaseBubble.activeSessions.get(params.session_id);
        if (!session) {
            return {
                operation: 'end_session',
                success: false,
                error: 'Session not found',
            };
        }
        try {
            // Disconnect browser first
            await session.browser.disconnect();
            // Release session via API and get the updated session data
            const sessionUpdateResponse = await this.browserbaseApi(`/sessions/${params.session_id}`, 'POST', {
                projectId: this.getConfig()?.projectId,
                status: 'REQUEST_RELEASE',
            });
            // Calculate session duration from API response (most accurate)
            // Use endedAt if available, otherwise use updatedAt as fallback
            const endTime = sessionUpdateResponse.endedAt
                ? new Date(sessionUpdateResponse.endedAt).getTime()
                : new Date(sessionUpdateResponse.updatedAt).getTime();
            const startTime = new Date(sessionUpdateResponse.startedAt).getTime();
            const sessionDurationMs = endTime - startTime;
            const sessionDurationMinutes = Math.max(0, sessionDurationMs / (1000 * 60)); // Ensure non-negative
            // Track service usage for browser session duration based on API response
            if (this.context?.logger && sessionDurationMinutes > 0) {
                this.context.logger.addServiceUsage({
                    service: CredentialType.BROWSERBASE_CRED,
                    unit: 'per_minute',
                    usage: sessionDurationMinutes,
                }, this.context.variableId);
                console.log(`[BrowserBaseBubble] Tracked session duration: ${sessionDurationMinutes.toFixed(2)} minutes (from API: startedAt=${sessionUpdateResponse.startedAt}, endedAt=${sessionUpdateResponse.endedAt || sessionUpdateResponse.updatedAt}) for session ${params.session_id}`);
            }
            // Emit browser session end event before closing
            if (this.context?.logger) {
                this.context.logger.logBrowserSessionEnd(params.session_id, this.context.variableId);
            }
            // Remove from active sessions
            BrowserBaseBubble.activeSessions.delete(params.session_id);
            console.log(`[BrowserBaseBubble] Session ${params.session_id} closed`);
            return {
                operation: 'end_session',
                success: true,
                error: '',
            };
        }
        catch (error) {
            return {
                operation: 'end_session',
                success: false,
                error: error instanceof Error
                    ? error.message
                    : 'Unknown error closing session',
            };
        }
    }
    chooseCredential() {
        const { credentials } = this.params;
        if (!credentials || typeof credentials !== 'object') {
            return undefined;
        }
        // BrowserBase bubble can use AMAZON_CRED (or other browser session creds)
        // to get contextId and cookies for session initialization
        return credentials[CredentialType.AMAZON_CRED];
    }
    /**
     * Get an active session by ID (for use by other bubbles)
     */
    static getSession(sessionId) {
        return BrowserBaseBubble.activeSessions.get(sessionId);
    }
    /**
     * Check if a session is active
     */
    static hasSession(sessionId) {
        return BrowserBaseBubble.activeSessions.has(sessionId);
    }
}
//# sourceMappingURL=browserbase.js.map