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 { z } from 'zod';
import { parseBrowserSessionData, buildProxyConfig } from '../_shared/utils.js';
import { LinkedInReceivedInvitationsToolParamsSchema, LinkedInReceivedInvitationsToolResultSchema, ReceivedInvitationInfoSchema, } from './schema.js';
let LinkedInReceivedInvitationsTool = (() => {
    let _classSuper = ToolBubble;
    let _instanceExtraInitializers = [];
    let _stepNavigateToReceivedInvitations_decorators;
    let _stepWaitForInvitationsPage_decorators;
    let _stepExtractAllInvitations_decorators;
    return class LinkedInReceivedInvitationsTool extends _classSuper {
        static {
            const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
            _stepNavigateToReceivedInvitations_decorators = [AIFallbackStep('Navigate to received invitations', {
                    taskDescription: 'Navigate to the LinkedIn received invitations page',
                })];
            _stepWaitForInvitationsPage_decorators = [AIFallbackStep('Wait for invitations to load', {
                    taskDescription: 'Wait for the received invitations list to fully load',
                })];
            _stepExtractAllInvitations_decorators = [AIFallbackStep('Extract all received invitations', {
                    taskDescription: 'Extract all received connection invitations by scrolling and clicking View more',
                    extractionSchema: z.array(ReceivedInvitationInfoSchema),
                })];
            __esDecorate(this, null, _stepNavigateToReceivedInvitations_decorators, { kind: "method", name: "stepNavigateToReceivedInvitations", static: false, private: false, access: { has: obj => "stepNavigateToReceivedInvitations" in obj, get: obj => obj.stepNavigateToReceivedInvitations }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _stepWaitForInvitationsPage_decorators, { kind: "method", name: "stepWaitForInvitationsPage", static: false, private: false, access: { has: obj => "stepWaitForInvitationsPage" in obj, get: obj => obj.stepWaitForInvitationsPage }, metadata: _metadata }, null, _instanceExtraInitializers);
            __esDecorate(this, null, _stepExtractAllInvitations_decorators, { kind: "method", name: "stepExtractAllInvitations", static: false, private: false, access: { has: obj => "stepExtractAllInvitations" in obj, get: obj => obj.stepExtractAllInvitations }, metadata: _metadata }, null, _instanceExtraInitializers);
            if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
        }
        static bubbleName = 'linkedin-received-invitations-tool';
        static schema = LinkedInReceivedInvitationsToolParamsSchema;
        static resultSchema = LinkedInReceivedInvitationsToolResultSchema;
        static shortDescription = 'Extract received LinkedIn connection invitations';
        static longDescription = 'Recordable LinkedIn Received Invitations Tool. Supports pagination via scrolling and "View more" / "Load more" button clicks.';
        static alias = 'linkedin-received-invitations';
        static type = 'tool';
        sessionId = (__runInitializers(this, _instanceExtraInitializers), null);
        contextId = null;
        cookies = null;
        constructor(params = { operation: 'get_received_invitations' }, context) {
            super(params, context);
        }
        chooseCredential() {
            const { credentials } = this.params;
            return credentials?.[CredentialType.LINKEDIN_CRED];
        }
        async stepStartBrowserSession() {
            if (this.sessionId)
                return;
            const sessionData = parseBrowserSessionData(this.chooseCredential());
            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 },
                timeout_seconds: 1200, // 10 minutes for full session (navigate + scroll + extract)
                ...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(`[RecordableReceivedInvitations] Session started: ${this.sessionId}`);
            const ip = await this.detectIPAddress();
            if (ip)
                console.log(`[RecordableReceivedInvitations] Browser IP: ${ip}`);
        }
        async stepNavigateToReceivedInvitations() {
            if (!this.sessionId)
                throw new Error('No active session');
            const browserbase = new BrowserBaseBubble({
                operation: 'navigate',
                session_id: this.sessionId,
                url: 'https://www.linkedin.com/mynetwork/invitation-manager/',
                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 stepWaitForInvitationsPage() {
            const checkScript = `(() => {
      const buttons = document.querySelectorAll('button');
      let hasAcceptButton = false;
      for (const btn of buttons) {
        if ((btn.innerText || btn.textContent || '').trim().toLowerCase() === 'accept') {
          hasAcceptButton = true;
          break;
        }
      }
      const peopleLabel = document.body.innerText.match(/People\\s*\\(\\d+\\)/i);
      return hasAcceptButton || !!peopleLabel;
    })()`;
            for (let attempt = 1; attempt <= 15; attempt++) {
                const found = await this.evaluate(checkScript);
                if (found)
                    return true;
                await new Promise((r) => setTimeout(r, 1000));
            }
            return false;
        }
        async stepExtractAllInvitations() {
            const MAX_SCROLL_ITERATIONS = 500;
            const MAX_STALE_ROUNDS = 10;
            const SCROLL_STEP = 1200;
            const SCROLL_WAIT_MS = 2200;
            let prevAcceptCount = 0;
            let staleRounds = 0;
            for (let iteration = 0; iteration < MAX_SCROLL_ITERATIONS; iteration++) {
                const scrollResult = (await this.evaluate(`
        (() => {
          const acceptCount = Array.from(document.querySelectorAll('button')).filter(btn =>
            (btn.innerText || btn.textContent || '').trim().toLowerCase() === 'accept'
          ).length;
          const scrollStep = ${SCROLL_STEP};
          const viewMoreLabels = ['view more', 'load more', 'see more', 'show more'];
          let viewMoreClicked = false;
          for (const el of document.querySelectorAll('button, span, div[role="button"], a')) {
            const text = (el.innerText || el.textContent || '').trim().toLowerCase();
            const ariaLabel = (el.getAttribute('aria-label') || '').trim().toLowerCase();
            const isViewMore = viewMoreLabels.some(l => text === l || ariaLabel === l);
            if (isViewMore && el.offsetParent !== null && !el.disabled) {
              el.click();
              viewMoreClicked = true;
              break;
            }
          }
          window.scrollBy(0, scrollStep);
          if (window.scrollY + window.innerHeight >= document.body.scrollHeight - 100) {
            window.scrollTo(0, document.body.scrollHeight);
          }
          const scrollableSet = new Set();
          document.querySelectorAll('button').forEach(btn => {
            if ((btn.innerText || btn.textContent || '').trim().toLowerCase() !== 'accept') return;
            let parent = btn.parentElement;
            for (let i = 0; i < 20 && parent; i++) {
              if (parent instanceof HTMLElement && parent.scrollHeight > parent.clientHeight + 100) {
                const s = window.getComputedStyle(parent);
                const oy = s.overflowY, o = s.overflow;
                if (oy === 'auto' || oy === 'scroll' || o === 'auto' || o === 'scroll') {
                  scrollableSet.add(parent);
                  break;
                }
              }
              parent = parent.parentElement;
            }
          });
          document.querySelectorAll('main, [role="main"]').forEach(el => scrollableSet.add(el));
          for (const el of scrollableSet) {
            if (el instanceof HTMLElement && el.scrollHeight > el.clientHeight && el.scrollHeight > 500) {
              const maxScroll = el.scrollHeight - el.clientHeight;
              el.scrollTop = Math.min(el.scrollTop + scrollStep, maxScroll);
              if (el.scrollTop + el.clientHeight >= el.scrollHeight - 100) {
                el.scrollTop = maxScroll;
              }
            }
          }
          return { acceptCount, viewMoreClicked };
        })()
      `));
                const currentCount = scrollResult.acceptCount;
                if (scrollResult.viewMoreClicked) {
                    console.log(`[RecordableReceivedInvitations] Clicked "View more" at scroll ${iteration + 1}`);
                }
                if (currentCount > prevAcceptCount) {
                    staleRounds = 0;
                }
                else {
                    staleRounds++;
                    if (staleRounds >= MAX_STALE_ROUNDS)
                        break;
                }
                prevAcceptCount = currentCount;
                const waitMs = scrollResult.viewMoreClicked ? 3200 : SCROLL_WAIT_MS;
                await new Promise((r) => setTimeout(r, waitMs));
            }
            const result = (await this.evaluate(`
      (() => {
        const invitations = [];
        const acceptButtons = Array.from(document.querySelectorAll('button')).filter(btn =>
          (btn.innerText || btn.textContent || '').trim().toLowerCase() === 'accept'
        );
        for (const acceptBtn of acceptButtons) {
          let container = acceptBtn.parentElement;
          for (let i = 0; i < 10 && container; i++) {
            const text = container.innerText || '';
            const hasProfileLink = !!container.querySelector('a[href*="/in/"]');
            const hasTimeText = !!(text.match(/\\d+\\s+(hour|day|week|month|minute|second)s?\\s+ago/i) || text.match(/Yesterday/i));
            if (hasProfileLink && hasTimeText) break;
            container = container.parentElement;
          }
          if (!container) continue;
          let profile_url = '';
          const links = container.querySelectorAll('a[href*="/in/"]');
          for (const link of links) {
            const href = link.getAttribute('href') || '';
            if (href.includes('/in/')) {
              profile_url = href.startsWith('http') ? href : 'https://www.linkedin.com' + href;
              break;
            }
          }
          let name = '';
          for (const link of links) {
            const linkText = (link.innerText || link.textContent || '').trim();
            if (linkText && linkText.length > 1 && linkText.length < 100) {
              name = linkText;
              break;
            }
          }
          if (!name) {
            const spans = container.querySelectorAll('span');
            for (const span of spans) {
              const spanText = (span.innerText || span.textContent || '').trim();
              if (spanText && spanText.length > 2 && spanText.length < 50 &&
                  !spanText.includes('Accept') && !spanText.includes('Ignore') &&
                  !spanText.includes('mutual') && !spanText.includes('ago') &&
                  !spanText.includes('Yesterday')) {
                name = spanText;
                break;
              }
            }
          }
          const containerText = container.innerText || '';
          let received_date = '';
          const timeMatch = containerText.match(/(\\d+\\s+(hour|day|week|month|minute|second)s?\\s+ago|Yesterday)/i);
          if (timeMatch) received_date = timeMatch[0];
          let mutual_connections = '';
          const mutualMatch = containerText.match(/(.+?(?:mutual connection|mutual connections))/i);
          if (mutualMatch) mutual_connections = mutualMatch[0].trim();
          const lines = containerText.split('\\n').map(l => l.trim()).filter(l => l);
          let headline = '';
          let nameLineIdx = -1, endLineIdx = -1;
          for (let i = 0; i < lines.length; i++) {
            if (lines[i] === name) nameLineIdx = i;
            if (endLineIdx === -1 && (
              lines[i].match(/\\d+\\s+(hour|day|week|month|minute|second)s?\\s+ago/i) ||
              lines[i].match(/Yesterday/i) ||
              lines[i].match(/mutual connection/i)
            )) endLineIdx = i;
          }
          if (nameLineIdx >= 0 && endLineIdx > nameLineIdx + 1) {
            headline = lines.slice(nameLineIdx + 1, endLineIdx)
              .filter(l => l.toLowerCase() !== 'accept' && l.toLowerCase() !== 'ignore' && l.length > 3)
              .join(' ').trim();
          }
          if (!headline) {
            for (const line of lines) {
              if (line === name || line.toLowerCase() === 'accept' || line.toLowerCase() === 'ignore' ||
                  line.match(/\\d+\\s+(hour|day|week|month|minute|second)s?\\s+ago/i) ||
                  line.match(/Yesterday/i) || line.match(/mutual connection/i) ||
                  line.match(/^People\\s*\\(/i)) continue;
              if (line.length > 10 && line.length < 300) { headline = line; break; }
            }
          }
          if (name) {
            invitations.push({
              name,
              headline: headline || undefined,
              mutual_connections: mutual_connections || undefined,
              received_date: received_date || 'Unknown',
              profile_url: profile_url || undefined,
            });
          }
        }
        let total = invitations.length;
        const allMatch = document.body.innerText.match(/All\\s*\\((\\d+)\\)/i);
        if (allMatch) total = parseInt(allMatch[1], 10);
        else {
          const peopleMatch = document.body.innerText.match(/People\\s*\\((\\d+)\\)/i);
          if (peopleMatch) total = parseInt(peopleMatch[1], 10);
        }
        const seen = new Set();
        const unique = [];
        for (const inv of invitations) {
          const key = inv.profile_url || inv.name;
          if (!seen.has(key)) { seen.add(key); unique.push(inv); }
        }
        return { invitations: unique, total };
      })()
    `));
            return result;
        }
        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(`[RecordableReceivedInvitations] 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 {
                return (await this.evaluate(`
        (async () => {
          try {
            const r = await fetch('https://api.ipify.org?format=json');
            const d = await r.json();
            return d.ip;
          } catch { return null; }
        })()
      `));
            }
            catch {
                return null;
            }
        }
        async performAction() {
            try {
                await this.stepStartBrowserSession();
                await this.stepNavigateToReceivedInvitations();
                const pageReady = await this.stepWaitForInvitationsPage();
                if (!pageReady)
                    console.log('[RecordableReceivedInvitations] Page slow to load, continuing');
                const { invitations, total } = await this.stepExtractAllInvitations();
                return {
                    operation: 'get_received_invitations',
                    success: true,
                    invitations,
                    total_count: total,
                    message: `Found ${invitations.length} received invitations`,
                    error: '',
                };
            }
            catch (error) {
                return {
                    operation: 'get_received_invitations',
                    success: false,
                    error: error instanceof Error ? error.message : 'Unknown error',
                };
            }
            finally {
                await this.stepEndBrowserSession();
            }
        }
    };
})();
export { LinkedInReceivedInvitationsTool };
//# sourceMappingURL=tool.js.map