import { Logger } from './logger.js';
import { AIClient } from './aiClient.js';
/**
 * Intelligent selector healing and fallback engine.
 */
export class Healer {
    /**
     * Attempts to find a working locator from a list of candidates.
     * Priority follows the enterprise standards (1-8).
     */
    static async heal(page, targets, aiConfig, failedAction) {
        Logger.log(`Starting self-healing for ${targets.length} candidates...`);
        for (const selector of targets) {
            if (!selector)
                continue;
            try {
                const locator = page.locator(selector);
                // Fail fast: Try to find the element within 1 second during healing phase
                const isFound = await locator.isVisible({ timeout: 1000 }).catch(() => false);
                if (isFound) {
                    Logger.log(`[HEALED] Successfully recovered element using: ${selector}`);
                    return locator;
                }
            }
            catch (err) {
                Logger.debug(`Healer candidate failed: ${selector}`);
            }
        }
        // Phase 2: AI-Powered Healing
        if (aiConfig && aiConfig.apiKey && failedAction) {
            Logger.log('[AI-HEAL] Attempting LLM-based selector recovery...');
            try {
                // Get a condensed DOM snippet for context
                const domSnippet = await page.evaluate(() => {
                    // Get the body HTML but remove scripts/styles to keep it small for LLM
                    const clone = document.body.cloneNode(true);
                    clone.querySelectorAll('script, style, svg, path, iframe').forEach(el => el.remove());
                    return clone.innerHTML.substring(0, 15000); // Limit to 15k chars for token efficiency
                });
                const suggestedSelector = await AIClient.getInstance().suggestHealedSelector(aiConfig, {
                    action: failedAction.action,
                    target: failedAction.target,
                    error: failedAction.error,
                    domSnippet
                });
                if (suggestedSelector && suggestedSelector !== 'NULL') {
                    Logger.log(`[AI-HEAL] LLM suggested new selector: ${suggestedSelector}`);
                    const aiLocator = page.locator(suggestedSelector);
                    const isFound = await aiLocator.isVisible({ timeout: 2000 }).catch(() => false);
                    if (isFound) {
                        Logger.log(`[AI-HEALED] Successfully recovered element using AI suggestion!`);
                        return aiLocator;
                    }
                }
            }
            catch (err) {
                Logger.error('[AI-HEAL] Failed during LLM recovery attempt');
            }
        }
        Logger.error('Self-healing failed: No working candidates found.');
        return null;
    }
    /**
     * Generates a ranked list of selectors for an element (in-browser part).
     * Note: This logic is partially mirrored in the recorder's client.js.
     */
    static getSelectorPriority(element) {
        const selectors = [];
        // 1. data-testid
        const testId = element.getAttribute('data-testid');
        if (testId)
            selectors.push(`[data-testid="${testId}"]`);
        // 2. aria-label
        const ariaLabel = element.getAttribute('aria-label');
        if (ariaLabel)
            selectors.push(`[aria-label="${ariaLabel}"]`);
        // 3. id (skipping dynamic ones)
        const id = element.id;
        if (id && !this.isDynamic(id))
            selectors.push(`#${id}`);
        // 4. name
        const name = element.getAttribute('name');
        if (name)
            selectors.push(`[name="${name}"]`);
        // 5. label text (placeholder logic)
        const placeholder = element.getAttribute('placeholder');
        if (placeholder)
            selectors.push(`[placeholder="${placeholder}"]`);
        // 6. visible text
        const text = element.innerText?.trim();
        if (text && text.length < 50)
            selectors.push(`text="${text}"`);
        // 7. CSS Fallback (simplified)
        const tag = element.tagName.toLowerCase();
        selectors.push(tag);
        return selectors;
    }
    static isDynamic(str) {
        // Basic check for dynamic IDs (e.g., ember123, uuid-style)
        return /[0-9]{4,}/.test(str) || /^[a-f0-9-]{36}$/.test(str);
    }
}
