import { Logger } from './logger.js';
/**
 * Extraction engine to pull structured data from the DOM using DSL rules.
 */
export class Extractor {
    /**
     * Normalizes keys by removing special characters and converting to snake_case.
     */
    static normalizeKey(key) {
        return key
            .trim()
            .replace(/[:]/g, '')
            .toLowerCase()
            .trim()
            .replace(/\s+/g, '_');
    }
    /**
     * Resolves a selector string from the config (handles string or DSLTarget).
     */
    static resolveSelector(target) {
        if (!target)
            return '';
        if (typeof target === 'string')
            return target;
        return target.css || (target.text ? `text="${target.text}"` : '');
    }
    /**
     * Extracts data from the current page based on DSL extraction configuration.
     */
    static async extract(page, config) {
        const results = {};
        const rootSelector = this.resolveSelector(config.root);
        if (!rootSelector) {
            Logger.error('Extraction failed: Root selector is missing');
            return {};
        }
        if (config.type === 'table_kv') {
            const rowSelector = this.resolveSelector(config.row);
            const keySelector = this.resolveSelector(config.key);
            const valSelector = this.resolveSelector(config.value);
            if (!rowSelector || !keySelector || !valSelector) {
                Logger.error('Missing selectors for table_kv extraction');
                return {};
            }
            const tableData = await page.$$eval(`${rootSelector} ${rowSelector}`, (rows, { kSel, vSel }) => {
                const pairs = [];
                rows.forEach((row) => {
                    const k = row.querySelector(kSel)?.textContent?.trim();
                    const v = row.querySelector(vSel)?.textContent?.trim();
                    if (k && v)
                        pairs.push([k, v]);
                });
                return pairs;
            }, { kSel: keySelector, vSel: valSelector });
            for (const [key, value] of tableData) {
                results[this.normalizeKey(key)] = value;
            }
        }
        else if (config.type === 'div_kv') {
            const rowSelector = this.resolveSelector(config.row) || '> div';
            const divData = await page.$eval(rootSelector, (root, rSel) => {
                const elements = root.querySelectorAll(rSel);
                const pairs = [];
                elements.forEach((el) => {
                    const text = el.innerText?.trim() || '';
                    const parts = text.split(/[:\n]/);
                    if (parts.length >= 2) {
                        pairs.push([parts[0].trim(), parts.slice(1).join(':').trim()]);
                    }
                });
                return pairs;
            }, rowSelector).catch(() => []);
            for (const [key, value] of divData) {
                const normalized = this.normalizeKey(key);
                if (!results[normalized]) {
                    results[normalized] = value;
                }
            }
        }
        return results;
    }
}
