var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
    var useValue = arguments.length > 2;
    for (var i = 0; i < initializers.length; i++) {
        value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
    }
    return useValue ? value : void 0;
};
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
    function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
    var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
    var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
    var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
    var _, done = false;
    for (var i = decorators.length - 1; i >= 0; i--) {
        var context = {};
        for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
        for (var p in contextIn.access) context.access[p] = contextIn.access[p];
        context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
        var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
        if (kind === "accessor") {
            if (result === void 0) continue;
            if (result === null || typeof result !== "object") throw new TypeError("Object expected");
            if (_ = accept(result.get)) descriptor.get = _;
            if (_ = accept(result.set)) descriptor.set = _;
            if (_ = accept(result.init)) initializers.unshift(_);
        }
        else if (_ = accept(result)) {
            if (kind === "field") initializers.unshift(_);
            else descriptor[key] = _;
        }
    }
    if (target) Object.defineProperty(target, contextIn.name, descriptor);
    done = true;
};
import { ToolBubble } from '../../../../types/tool-bubble-class.js';
import { AIFallbackStep } from '../_shared/ai/ai-fallback-step.js';
import { BrowserBaseBubble, } from '../../../service-bubble/browserbase/index.js';
import { CredentialType } from '@bubblelab/shared-schemas';
import { parseBrowserSessionData, buildProxyConfig } from '../_shared/utils.js';
import { LinkedInConnectionToolParamsSchema, LinkedInConnectionToolResultSchema, ProfileInfoSchema, } from './schema.js';
/**
 * Recordable LinkedIn Connection Tool
 *
 * A tool bubble for automating LinkedIn connection requests with step recording.
 * Each major action is decorated with @RecordableStep to capture before/after
 * screenshots, URLs, and timing information.
 */
let LinkedInConnectionTool = (() => {
    let _classSuper = ToolBubble;
    let _instanceExtraInitializers = [];
    let _stepNavigateToProfile_decorators;
    let _stepWaitForProfilePage_decorators;
    let _stepExtractProfileInfo_decorators;
    let _stepClickConnect_decorators;
    let _stepWaitForModal_decorators;
    let _stepAddNote_decorators;
    let _stepSendRequest_decorators;
    return class LinkedInConnectionTool extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _stepNavigateToProfile_decorators = [AIFallbackStep('Navigate to profile', {
                    taskDescription: 'Navigate to the LinkedIn profile URL and wait for page to load',
                })];
            _stepWaitForProfilePage_decorators = [AIFallbackStep('Wait for profile page', {
                    taskDescription: 'Wait for LinkedIn profile page to fully load with action buttons (Connect, Message, Follow)',
                })];
            _stepExtractProfileInfo_decorators = [AIFallbackStep('Extract profile info', {
                    taskDescription: 'Extract the LinkedIn profile name, headline, and location from the profile page',
                    extractionSchema: ProfileInfoSchema,
                })];
            _stepClickConnect_decorators = [AIFallbackStep('Click Connect button', {
                    taskDescription: 'Find and click the Connect button to send a connection request. If there is no visible "Connect" button, first click the "More" button to open the dropdown menu, then click "Connect" inside the dropdown. The goal is to open the connection request modal.',
                })];
            _stepWaitForModal_decorators = [AIFallbackStep('Wait for connection modal', {
                    taskDescription: 'Wait for the connection modal to appear with "Add a note" or "Send without a note" buttons',
                })];
            _stepAddNote_decorators = [AIFallbackStep('Add note to connection', {
                    taskDescription: 'Click "Add a note" button and type the personalized message into the textarea',
                })];
            _stepSendRequest_decorators = [AIFallbackStep('Send connection request', {
                    taskDescription: 'Click the Send button to submit the connection request. Look for a blue "Send" button or "Send without a note" button in the connection modal.',
                })];
            __esDecorate(this, null, _stepNavigateToProfile_decorators, { kind: "method", name: "stepNavigateToProfile", static: false, private: false, access: { has: obj => "stepNavigateToProfile" in obj, get: obj => obj.stepNavigateToProfile }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _stepWaitForProfilePage_decorators, { kind: "method", name: "stepWaitForProfilePage", static: false, private: false, access: { has: obj => "stepWaitForProfilePage" in obj, get: obj => obj.stepWaitForProfilePage }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _stepExtractProfileInfo_decorators, { kind: "method", name: "stepExtractProfileInfo", static: false, private: false, access: { has: obj => "stepExtractProfileInfo" in obj, get: obj => obj.stepExtractProfileInfo }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _stepClickConnect_decorators, { kind: "method", name: "stepClickConnect", static: false, private: false, access: { has: obj => "stepClickConnect" in obj, get: obj => obj.stepClickConnect }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _stepWaitForModal_decorators, { kind: "method", name: "stepWaitForModal", static: false, private: false, access: { has: obj => "stepWaitForModal" in obj, get: obj => obj.stepWaitForModal }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _stepAddNote_decorators, { kind: "method", name: "stepAddNote", static: false, private: false, access: { has: obj => "stepAddNote" in obj, get: obj => obj.stepAddNote }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _stepSendRequest_decorators, { kind: "method", name: "stepSendRequest", static: false, private: false, access: { has: obj => "stepSendRequest" in obj, get: obj => obj.stepSendRequest }, metadata: _metadata }, null, _instanceExtraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        static bubbleName = 'linkedin-connection-tool';
        static schema = LinkedInConnectionToolParamsSchema;
        static resultSchema = LinkedInConnectionToolResultSchema;
        static shortDescription = 'LinkedIn connection automation with step recording';
        static longDescription = `
    Recordable LinkedIn Connection Tool for automating connection requests.
    Records each step with screenshots and timing information for debugging.
  `;
        static alias = 'linkedin-recordable';
        static type = 'tool';
        /** JS helper to query elements across main document, iframes, and shadow DOM */
        static CROSS_DOM_QUERY = `
    function queryAllDOMs(selector) {
      const results = [...document.querySelectorAll(selector)];
      for (const iframe of document.querySelectorAll('iframe')) {
        try {
          if (iframe.contentDocument) {
            results.push(...iframe.contentDocument.querySelectorAll(selector));
          }
        } catch(e) {}
      }
      const shadowHost = document.querySelector('[data-testid="interop-shadowdom"]');
      if (shadowHost && shadowHost.shadowRoot) {
        results.push(...shadowHost.shadowRoot.querySelectorAll(selector));
      }
      return results;
    }
  `;
        sessionId = (__runInitializers(this, _instanceExtraInitializers), null);
        contextId = null;
        cookies = null;
        constructor(params = { operation: 'send_connection', profile_url: '' }, context) {
            super(params, context);
        }
        /** Required by RecordableToolBubble - returns the active browser session ID */
        chooseCredential() {
            const { credentials } = this.params;
            if (!credentials || typeof credentials !== 'object') {
                return undefined;
            }
            return credentials[CredentialType.LINKEDIN_CRED];
        }
        parseBrowserSessionData() {
            return parseBrowserSessionData(this.chooseCredential());
        }
        // ==================== RECORDABLE STEPS ====================
        async stepStartBrowserSession() {
            if (this.sessionId)
                return;
            const sessionData = this.parseBrowserSessionData();
            if (sessionData) {
                this.contextId = sessionData.contextId;
                this.cookies = sessionData.cookies;
            }
            const proxyConfig = buildProxyConfig(this.params.proxy);
            const browserbase = new BrowserBaseBubble({
                operation: 'start_session',
                context_id: this.contextId || undefined,
                cookies: this.cookies || undefined,
                credentials: this.params.credentials,
                stealth: { solveCaptchas: true },
                ...proxyConfig,
            }, this.context, 'startsession');
            const result = await browserbase.action();
            if (!result.data.success || !result.data.session_id) {
                throw new Error(result.data.error || 'Failed to start browser session');
            }
            this.sessionId = result.data.session_id;
            if (result.data.context_id) {
                this.contextId = result.data.context_id;
            }
            console.log(`[RecordableLinkedIn] Session started: ${this.sessionId}`);
            const ipAddress = await this.detectIPAddress();
            if (ipAddress) {
                console.log(`[RecordableLinkedIn] Browser IP: ${ipAddress}`);
            }
        }
        async stepNavigateToProfile() {
            if (!this.sessionId)
                throw new Error('No active session');
            const browserbase = new BrowserBaseBubble({
                operation: 'navigate',
                session_id: this.sessionId,
                url: this.params.profile_url,
                wait_until: 'domcontentloaded',
                timeout: 30000,
            }, this.context, 'navigate');
            const result = await browserbase.action();
            if (!result.data.success) {
                throw new Error(result.data.error || 'Navigation failed');
            }
        }
        async stepWaitForProfilePage() {
            const checkScript = `
      (() => {
        const elements = document.querySelectorAll('button, a, [role="button"]');
        for (const el of elements) {
          const ariaLabel = (el.getAttribute('aria-label') || '').toLowerCase();
          const text = (el.innerText || el.textContent || '').trim().toLowerCase();
          if (ariaLabel.includes('connect') || text === 'connect') return true;
          if (ariaLabel === 'more' || ariaLabel.includes('more actions')) return true;
          if (text === 'message' || ariaLabel.includes('message')) return true;
          if (text === 'follow' || ariaLabel.includes('follow')) return true;
        }
        return false;
      })()
    `;
            for (let attempt = 1; attempt <= 30; attempt++) {
                const found = await this.evaluate(checkScript);
                if (found)
                    return true;
                await new Promise((r) => setTimeout(r, 1000));
            }
            return false;
        }
        async stepExtractProfileInfo() {
            const info = (await this.evaluate(`
      (() => {
        let name = '';
        const h1El = document.querySelector('h1');
        if (h1El) name = h1El.textContent?.trim() || '';

        let headline = '';
        const headlineEl = document.querySelector('div.text-body-medium.break-words');
        if (headlineEl) headline = headlineEl.textContent?.trim() || '';

        let location = '';
        const spans = document.querySelectorAll('span');
        for (const span of spans) {
          const text = span.textContent?.trim() || '';
          if (text.includes(',') && text.length < 100 && text.length > 5) {
            if (/(?:United|Kingdom|States|England|Germany|France|India|Canada|Australia)/i.test(text)) {
              location = text;
              break;
            }
          }
        }

        return { name, headline, location, profile_url: window.location.href };
      })()
    `));
            return info.name ? info : null;
        }
        async stepClickConnect() {
            // Primary: find <a> with custom-invite href (new LinkedIn design)
            const directResult = (await this.evaluate(`
      (() => {
        // New LinkedIn design: Connect is an <a> with /custom-invite/ href
        const connectLink = document.querySelector('a[href*="/custom-invite/"]');
        if (connectLink) {
          connectLink.click();
          return { clicked: true, element: 'A - ' + (connectLink.getAttribute('aria-label') || 'custom-invite') };
        }

        // Fallback: search all clickable elements by aria-label or text
        const elements = document.querySelectorAll('button, a, [role="button"]');
        for (const el of elements) {
          const ariaLabel = (el.getAttribute('aria-label') || '').toLowerCase();
          const text = (el.innerText || el.textContent || '').trim().toLowerCase();
          if ((ariaLabel.includes('invite') && ariaLabel.includes('connect')) ||
              text === 'connect') {
            const rect = el.getBoundingClientRect();
            if (rect.width > 0 && rect.height > 0) {
              el.click();
              return { clicked: true, element: el.tagName + ' - ' + (ariaLabel || text) };
            }
          }
        }
        return { clicked: false };
      })()
    `));
            if (directResult.clicked)
                return true;
            // More dropdown fallback
            const moreResult = (await this.evaluate(`
      (() => {
        const elements = document.querySelectorAll('button, a, [role="button"]');
        for (const el of elements) {
          const ariaLabel = (el.getAttribute('aria-label') || '').toLowerCase();
          const text = (el.innerText || el.textContent || '').trim().toLowerCase();
          if (ariaLabel === 'more' || ariaLabel.includes('more actions') || text === 'more') {
            el.click();
            return { clicked: true, element: ariaLabel || text };
          }
        }
        return { clicked: false };
      })()
    `));
            if (moreResult.clicked) {
                await new Promise((r) => setTimeout(r, 1000));
                const dropdownResult = (await this.evaluate(`
        (() => {
          // Search dropdown items, menu items, and list items for Connect
          const items = document.querySelectorAll('[role="button"], [role="menuitem"], [role="option"], li a, li button');
          for (const item of items) {
            const ariaLabel = (item.getAttribute('aria-label') || '').toLowerCase();
            const text = (item.innerText || item.textContent || '').trim().toLowerCase();
            if ((ariaLabel.includes('invite') && ariaLabel.includes('connect')) ||
                ariaLabel.includes('connect') || text === 'connect') {
              item.click();
              return { clicked: true, element: ariaLabel || text };
            }
          }
          return { clicked: false, itemCount: items.length };
        })()
      `));
                if (dropdownResult.clicked)
                    return true;
                throw new Error(`Could not find Connect option in More dropdown (found ${dropdownResult.itemCount} items)`);
            }
            throw new Error('Could not find Connect button or More dropdown');
        }
        async stepWaitForModal() {
            const checkScript = `
      (() => {
        ${LinkedInConnectionTool.CROSS_DOM_QUERY}
        const elements = queryAllDOMs('button, a, [role="button"]');
        for (const el of elements) {
          const text = (el.innerText || el.textContent || '').trim().toLowerCase();
          if (text.includes('add a note') || text.includes('send without')) return true;
        }
        return false;
      })()
    `;
            for (let attempt = 1; attempt <= 8; attempt++) {
                const found = await this.evaluate(checkScript);
                if (found)
                    return true;
                await new Promise((r) => setTimeout(r, 1000));
            }
            throw new Error('Connection modal did not appear within 8 seconds');
        }
        async stepAddNote(message) {
            await this.evaluate(`
      (() => {
        ${LinkedInConnectionTool.CROSS_DOM_QUERY}
        const elements = queryAllDOMs('button, a, [role="button"]');
        for (const el of elements) {
          const text = (el.innerText || el.textContent || '').trim().toLowerCase();
          if (text.includes('add a note')) {
            el.click();
            return true;
          }
        }
        return false;
      })()
    `);
            await new Promise((r) => setTimeout(r, 500));
            await this.evaluate(`
      (() => {
        ${LinkedInConnectionTool.CROSS_DOM_QUERY}
        const textareas = queryAllDOMs('textarea');
        const textarea = textareas.find(t => {
          const rect = t.getBoundingClientRect();
          return rect.width > 0 && rect.height > 0;
        }) || textareas[0];
        if (textarea) {
          textarea.value = ${JSON.stringify(message)};
          textarea.dispatchEvent(new Event('input', { bubbles: true }));
          return true;
        }
        return false;
      })()
    `);
        }
        async stepSendRequest(withNote) {
            if (withNote) {
                const result = (await this.evaluate(`
        (() => {
          ${LinkedInConnectionTool.CROSS_DOM_QUERY}
          const elements = queryAllDOMs('button, a, [role="button"]');
          for (const el of elements) {
            const text = (el.innerText || el.textContent || '').trim().toLowerCase();
            if (text === 'send') {
              el.click();
              return { clicked: true };
            }
          }
          return { clicked: false };
        })()
      `));
                if (!result.clicked)
                    throw new Error('Could not find Send button in modal');
                return true;
            }
            else {
                const result = (await this.evaluate(`
        (() => {
          ${LinkedInConnectionTool.CROSS_DOM_QUERY}
          const elements = queryAllDOMs('button, a, [role="button"]');
          for (const el of elements) {
            const text = (el.innerText || el.textContent || '').trim().toLowerCase();
            if (text.includes('send without')) {
              el.click();
              return { clicked: true };
            }
          }
          return { clicked: false };
        })()
      `));
                if (!result.clicked)
                    throw new Error('Could not find "Send without a note" button in modal');
                return true;
            }
        }
        async stepEndBrowserSession() {
            if (!this.sessionId)
                return;
            const browserbase = new BrowserBaseBubble({
                operation: 'end_session',
                session_id: this.sessionId,
            }, this.context, 'endsession');
            await browserbase.action();
            console.log(`[RecordableLinkedIn] Session ended: ${this.sessionId}`);
            this.sessionId = null;
        }
        async evaluate(script) {
            if (!this.sessionId)
                throw new Error('No active session');
            const browserbase = new BrowserBaseBubble({
                operation: 'evaluate',
                session_id: this.sessionId,
                script,
            }, this.context, 'evaluate');
            const result = await browserbase.action();
            if (!result.data.success) {
                throw new Error(result.data.error || 'Evaluation failed');
            }
            return result.data.result;
        }
        async detectIPAddress() {
            if (!this.sessionId)
                return null;
            try {
                const result = await this.evaluate(`
        (async () => {
          try {
            const response = await fetch('https://api.ipify.org?format=json');
            const data = await response.json();
            return data.ip;
          } catch (e) {
            return null;
          }
        })()
      `);
                return result;
            }
            catch {
                return null;
            }
        }
        async performAction() {
            try {
                await this.stepStartBrowserSession();
                await this.stepNavigateToProfile();
                const pageReady = await this.stepWaitForProfilePage();
                if (!pageReady) {
                    console.log('[RecordableLinkedIn] Profile page slow to load, continuing anyway');
                }
                const profileInfo = await this.stepExtractProfileInfo();
                await this.stepClickConnect();
                await this.stepWaitForModal();
                const { message } = this.params;
                if (message) {
                    await this.stepAddNote(message);
                }
                await this.stepSendRequest(!!message);
                return {
                    operation: 'send_connection',
                    success: true,
                    message: `Connection request sent to ${profileInfo?.name || 'profile'}`,
                    profile: profileInfo || undefined,
                    error: '',
                };
            }
            catch (error) {
                return {
                    operation: 'send_connection',
                    success: false,
                    error: error instanceof Error ? error.message : 'Unknown error',
                };
            }
            finally {
                await this.stepEndBrowserSession();
            }
        }
    };
})();
export { LinkedInConnectionTool };
//# sourceMappingURL=tool.js.map