import * as fs from 'fs';
import * as path from 'path';
import { Logger } from '../utils/logger.js';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
/**
 * Enterprise DSL & Scenario Compiler.
 */
export class Compiler {
    /**
     * Compiles raw events into framework assets.
     */
    static compile(events, siteName) {
        if (events.length === 0) {
            Logger.warn('Compiler: No events provided. Skipping generation.');
            return;
        }
        Logger.log(`Compiling ${events.length} events for ${siteName}...`);
        const compiledSteps = [];
        const inputData = {};
        const baseUrl = events[0]?.url || '';
        let i = 0;
        while (i < events.length) {
            const event = events[i];
            if (event.type === 'startLoop') {
                // Find matching finalizeLoop
                let loopSteps = [];
                let j = i + 1;
                while (j < events.length && events[j].type !== 'finalizeLoop') {
                    const le = events[j];
                    loopSteps.push({
                        action: this.mapAction(le.type),
                        target: le.selector,
                        value: le.value,
                        attribute: le.attribute,
                        captchaConfig: le.captchaConfig,
                    });
                    j++;
                }
                const finalizeStep = events[j] || {};
                compiledSteps.push({
                    action: 'scrapeDeep',
                    target: finalizeStep.selector,
                    paginateTarget: finalizeStep.paginateTarget,
                    label: finalizeStep.label || 'deep_loop',
                    steps: loopSteps
                });
                i = j + 1;
            }
            else if (event.type === 'finalizeLoop') {
                i++;
            }
            else {
                const step = {
                    action: this.mapAction(event.type),
                    target: event.selector,
                    value: event.value,
                    label: event.label,
                    attribute: event.attribute,
                    regex: event.regex,
                    code: event.code,
                    timeout: event.timeout,
                    frame: event.frame,
                    optional: event.type === 'validate' || event.type === 'assert' ? true : false,
                    captchaConfig: event.captchaConfig,
                };
                if (event.type === 'input' || event.type === 'type') {
                    const key = this.inferInputKey(event);
                    step.inputKey = key;
                    inputData[key] = event.value || '';
                }
                compiledSteps.push(step);
                i++;
            }
        }
        // 1. Generate DSL
        const dsl = {
            baseUrl,
            flows: {
                recorded_flow: { name: 'recorded_flow', steps: compiledSteps }
            }
        };
        // 2. Generate Scenario
        const scenario = {
            mode: 'scrape',
            name: siteName,
            baseUrl: baseUrl,
            flows: ['recorded_flow'],
            inputFile: `${siteName}.inputs.json`,
            expectedFile: `${siteName}.expected.json`
        };
        // 3. Infer Expectations
        const expected = this.inferExpectations(events);
        this.saveAssets(siteName, dsl, scenario, [inputData], expected);
    }
    /**
     * Infers expected outcomes from event patterns.
     */
    static inferExpectations(events) {
        const lastUrl = events[events.length - 1]?.url || '';
        // Simple heuristic: if we ended on a different URL than we started, assume success navigation
        if (lastUrl !== events[0].url && (lastUrl.includes('dashboard') || lastUrl.includes('home'))) {
            return [{ type: 'success' }];
        }
        // Default to success if no error seen
        return [{ type: 'success' }];
    }
    /**
     * Infers a semantic key for an input based on attributes.
     */
    static inferInputKey(event) {
        const raw = (event.selector || '').toLowerCase();
        if (raw.includes('user'))
            return 'username';
        if (raw.includes('pass'))
            return 'password';
        if (raw.includes('email'))
            return 'email';
        if (raw.includes('search') || raw.includes('query'))
            return 'query';
        // Fallback to timestamp-based key if no semantic match
        return `input_${event.timestamp}`;
    }
    static mapAction(type) {
        const map = {
            'scrape_prop': 'scrapeProp',
            'scrape_attr': 'scrapeAttr',
            'drag_drop': 'drag_and_drop',
            'double_click': 'double_click',
            'dbClick': 'double_click',
            'right_click': 'right_click',
            'scrape_pairs': 'scrapePairs'
        };
        return map[type] || type;
    }
    static saveAssets(name, dsl, scenario, inputs, expected) {
        const sitesDir = path.resolve(__dirname, '../../config/sites');
        const dataDir = path.resolve(__dirname, '../../data');
        const scenariosDir = path.resolve(__dirname, '../../scenarios');
        if (!fs.existsSync(sitesDir))
            fs.mkdirSync(sitesDir, { recursive: true });
        if (!fs.existsSync(dataDir))
            fs.mkdirSync(dataDir, { recursive: true });
        if (!fs.existsSync(scenariosDir))
            fs.mkdirSync(scenariosDir, { recursive: true });
        fs.writeFileSync(path.join(sitesDir, `${name}.dsl.json`), JSON.stringify(dsl, null, 2));
        fs.writeFileSync(path.join(dataDir, `${name}.inputs.json`), JSON.stringify(inputs, null, 2));
        fs.writeFileSync(path.join(dataDir, `${name}.expected.json`), JSON.stringify(expected, null, 2));
        fs.writeFileSync(path.join(scenariosDir, `${name}.scenario.json`), JSON.stringify(scenario, null, 2));
        Logger.log(`Compilation complete. Generated assets for site: ${name}`);
    }
}
