import { LibraryRegistry } from '../utilities/library-registry.js';
import { LibraryLoader } from '../utilities/library-loader.js';
import { unwrapLibraryComponent, unwrapLibraryComponents, unwrapAllLibraryComponents } from '../utilities/component-unwrapper.js';
const DEFAULT_COMPILER_CONFIG = {
    babel: {
        presets: ['react'],
        plugins: []
    },
    minify: false,
    sourceMaps: true,
    cache: true,
    maxCacheSize: 100,
    debug: false
};
export class ComponentCompiler {
    constructor(config) {
        this.CORE_LIBRARIES = new Set(['React', 'ReactDOM']);
        this.config = { ...DEFAULT_COMPILER_CONFIG, ...config };
        this.compilationCache = new Map();
    }
    setBabelInstance(babel) {
        this.babelInstance = babel;
    }
    async compile(options) {
        const startTime = Date.now();
        try {
            if (this.config.cache) {
                const cached = this.getCachedComponent(options.componentName, options.componentCode);
                if (cached) {
                    return {
                        success: true,
                        component: cached,
                        duration: Date.now() - startTime
                    };
                }
            }
            this.validateCompileOptions(options);
            const loadedLibraries = await this.loadRequiredLibraries(options.libraries, options.allLibraries);
            const transpiled = this.transpileComponent(options.componentCode, options.componentName, options);
            const componentFactory = this.createComponentFactory(transpiled.code, options.componentName, loadedLibraries, options);
            const compiledComponent = {
                factory: componentFactory,
                id: this.generateComponentId(options.componentName),
                name: options.componentName,
                compiledAt: new Date(),
                warnings: [],
                sourceMap: transpiled.map
            };
            if (this.config.cache) {
                this.cacheComponent(compiledComponent, options.componentCode);
            }
            return {
                success: true,
                component: compiledComponent,
                duration: Date.now() - startTime,
                size: transpiled.code.length,
                loadedLibraries: loadedLibraries
            };
        }
        catch (error) {
            return {
                success: false,
                error: this.createCompilationError(error, options.componentName),
                duration: Date.now() - startTime
            };
        }
    }
    transpileComponent(code, componentName, options) {
        if (!this.babelInstance) {
            throw new Error('Babel instance not set. Call setBabelInstance() first.');
        }
        const wrappedCode = this.wrapComponentCode(code, componentName, options.libraries, options.dependencies);
        try {
            const result = this.babelInstance.transform(wrappedCode, {
                presets: options.babelPresets || this.config.babel.presets,
                plugins: options.babelPlugins || this.config.babel.plugins,
                filename: `${componentName}.jsx`,
                sourceMaps: this.config.sourceMaps,
                minified: this.config.minify
            });
            return { code: result.code, map: result.map };
        }
        catch (error) {
            throw new Error(`Transpilation failed: ${error.message}`);
        }
    }
    wrapComponentCode(componentCode, componentName, libraries, dependencies) {
        const debug = this.config.debug;
        const libraryDeclarations = libraries && libraries.length > 0
            ? libraries
                .filter(lib => lib.globalVariable && !this.CORE_LIBRARIES.has(lib.globalVariable))
                .map(lib => `const ${lib.globalVariable} = libraries['${lib.globalVariable}'];`)
                .join('\n        ')
            : '';
        const libraryLogChecks = libraries && libraries.length > 0
            ? libraries
                .filter(lib => lib.globalVariable && !this.CORE_LIBRARIES.has(lib.globalVariable))
                .map(lib => `\nif (!${lib.globalVariable}) { console.error('[React-Runtime-JS] Library "${lib.globalVariable}" is not defined'); } else { ${debug ? `console.log('[React-Runtime-JS] Library "${lib.globalVariable}" is defined');` : ''} }`)
                .join('\n        ')
            : '';
        const seenDependencies = new Set();
        const uniqueDependencies = [];
        const duplicates = [];
        if (dependencies && dependencies.length > 0) {
            for (const dep of dependencies) {
                if (dep.name === componentName) {
                    continue;
                }
                if (seenDependencies.has(dep.name)) {
                    duplicates.push(dep.name);
                }
                else {
                    seenDependencies.add(dep.name);
                    uniqueDependencies.push(dep);
                }
            }
        }
        const duplicateWarnings = duplicates.length > 0
            ? duplicates
                .map(name => `console.warn('[React-Runtime-JS] WARNING: Component "${name}" is registered multiple times as a dependency. Using first occurrence only.');`)
                .join('\n        ')
            : '';
        const componentDeclarations = uniqueDependencies.length > 0
            ? uniqueDependencies
                .map(dep => `const ${dep.name}Raw = componentsOuter['${dep.name}'];
        ${debug ? `console.log('[React-Runtime-JS] Extracting ${dep.name}:');
        console.log('  - Raw value type:', typeof ${dep.name}Raw);
        console.log('  - Raw value:', ${dep.name}Raw);
        if (${dep.name}Raw && typeof ${dep.name}Raw === 'object') {
          console.log('  - Has .component property:', 'component' in ${dep.name}Raw);
          console.log('  - .component type:', typeof ${dep.name}Raw.component);
        }` : ''}
        const ${dep.name}Unwrapped = ${dep.name}Raw?.component || ${dep.name}Raw;
        const ${dep.name} = (props) => React.createElement(
          'div',
          { 'data-mj-component': '${dep.name}', style: { display: 'contents' } },
          React.createElement(${dep.name}Unwrapped, props)
        );
        ${debug ? `console.log('  - Final ${dep.name} type:', typeof ${dep.name});
        console.log('  - Final ${dep.name} is function:', typeof ${dep.name} === 'function');` : ''}`)
                .join('\n        ')
            : '';
        const componentLogChecks = uniqueDependencies.length > 0
            ? uniqueDependencies
                .map(dep => `if (!${dep.name}) { console.error('[React-Runtime-JS] Dependency "${dep.name}" is not defined'); } else { ${debug ? `console.log('[React-Runtime-JS] Dependency "${dep.name}" is defined');` : ''} }`)
                .join('\n        ')
            : '';
        const wrappedCode = `
      function createComponent(
        React, ReactDOM, 
        useState, useEffect, useCallback, useMemo, useRef, useContext, useReducer, useLayoutEffect,
        libraries, styles, console, components,
        unwrapLibraryComponent, unwrapLibraryComponents, unwrapAllLibraryComponents
      ) {
        if (!React)
            console.log('[React-Runtime-JS] React is not defined');
        if (!ReactDOM)
            console.log('[React-Runtime-JS] ReactDOM is not defined');

        // Make unwrap functions available with legacy names for backward compatibility
        const unwrapComponent = unwrapLibraryComponent;
        const unwrapComponents = unwrapLibraryComponents;
        const unwrapAllComponents = unwrapAllLibraryComponents;
        
        // Code for ${componentName}
        ${componentCode}
        
        // Ensure the component exists
        if (typeof ${componentName} === 'undefined') {
          throw new Error('Component "${componentName}" is not defined in the provided code');
        }
        else {
          ${debug ? `console.log('[React-Runtime-JS] Component "${componentName}" is defined');` : ''}
        }
        
        // Store the component in a variable so we don't lose it
        const UserComponent = ${componentName};

        // Check if the component is already a ComponentObject (has a .component property)
        // If so, extract the actual React component
        const ActualComponent = (typeof UserComponent === 'object' && UserComponent !== null && 'component' in UserComponent)
          ? UserComponent.component
          : UserComponent;
        
        // Debug logging to understand what we're getting
        ${debug ? `
        console.log('[React-Runtime-JS]Component ${componentName} type:', typeof UserComponent);
        if (typeof UserComponent === 'object' && UserComponent !== null) {
          console.log('[React-Runtime-JS]Component ${componentName} keys:', Object.keys(UserComponent));
          console.log('[React-Runtime-JS]Component ${componentName} has .component:', 'component' in UserComponent);
          if ('component' in UserComponent) {
            console.log('[React-Runtime-JS]Component ${componentName}.component type:', typeof UserComponent.component);
          }
        }` : ''}
        
        // Validate that we have a function (React component)
        if (typeof ActualComponent !== 'function') {
          console.error('[React-Runtime-JS] Invalid component type for ${componentName}:', typeof ActualComponent);
          console.error('[React-Runtime-JS] ActualComponent value:', ActualComponent);
          console.error('[React-Runtime-JS] Original UserComponent value:', UserComponent);
          throw new Error('[React-Runtime-JS] Component "${componentName}" must be a function (React component) or an object with a .component property that is a function. Got: ' + typeof ActualComponent);
        }

        let componentsOuter = null, utilitiesOuter = null;
        const DestructureWrapperUserComponent = (props) => {
          if (!componentsOuter) {
            componentsOuter = props?.components || components;
          }
          if (!utilitiesOuter) {
            utilitiesOuter = props?.utilities;
          }
          ${debug ? `
          console.log('[React-Runtime-JS] DestructureWrapperUserComponent for ${componentName}:');
          console.log('  - Props:', props);
          console.log('  - componentsOuter type:', typeof componentsOuter);
          console.log('  - componentsOuter:', componentsOuter);
          if (componentsOuter && typeof componentsOuter === 'object') {
            console.log('  - componentsOuter keys:', Object.keys(componentsOuter));
            for (const key of Object.keys(componentsOuter)) {
              const comp = componentsOuter[key];
              console.log(\`  - componentsOuter[\${key}] type:\`, typeof comp);
              if (comp && typeof comp === 'object') {
                console.log(\`    - Has .component: \${'component' in comp}\`);
                console.log(\`    - .component type: \${typeof comp.component}\`);
              }
            }
          }
          console.log('  - styles:', styles);
          console.log('  - utilities:', utilitiesOuter);
          console.log('  - libraries:', libraries);` : ''}
          ${duplicateWarnings ? '// Duplicate dependency warnings\n        ' + duplicateWarnings + '\n        ' : ''}
          ${libraryDeclarations ? '// Destructure Libraries\n' + libraryDeclarations + '\n        ' : ''}
          ${componentDeclarations ? '// Destructure Dependencies\n' + componentDeclarations + '\n        ' : ''}
          ${libraryLogChecks}
          ${componentLogChecks}          

          const newProps = {
            ...props,
            components: componentsOuter,
            utilities: utilitiesOuter 
          }
          return ActualComponent(newProps);
        };
        
        // Create a fresh method registry for each factory call
        const methodRegistry = new Map();
        
        // Create a wrapper component that provides RegisterMethod in callbacks.
        // NOTE: Do NOT clear methodRegistry inside an effect here. React runs
        // child effects before parent effects, so the user component's mount
        // effect (which calls RegisterMethod) fires before this wrapper effect.
        // A clear() here would wipe out the just-registered methods and break
        // hasMethod()/invokeMethod(). Cleanup is handled by the component's own
        // re-renders and by garbage collection when the factory closure is freed.
        const ComponentWithMethodRegistry = (props) => {
          // Create enhanced callbacks with RegisterMethod
          const enhancedCallbacks = React.useMemo(() => {
            if (!props.callbacks) return {};
            
            return {
              ...props.callbacks,
              RegisterMethod: (methodName, handler) => {
                if (methodName && handler) {
                  methodRegistry.set(methodName, handler);
                }
              }
            };
          }, [props.callbacks]);
          
          // Render the original component with enhanced callbacks, wrapped in a DOM marker div
          return React.createElement('div', {
            'data-mj-component': '${componentName}',
            'data-mj-root': 'true',
            style: { display: 'contents' }
          }, React.createElement(DestructureWrapperUserComponent, {
            ...props,
            callbacks: enhancedCallbacks
          }));
        };

        ComponentWithMethodRegistry.displayName = '${componentName}WithMethods';
        
        // Return the component object with method access
        return {
          component: ComponentWithMethodRegistry,
          
          print: function() { 
            const printMethod = methodRegistry.get('print');
            if (printMethod) {
              printMethod();
            } else if (typeof window !== 'undefined' && window.print) {
              window.print(); 
            }
          },
          refresh: function(data) { 
            const refreshMethod = methodRegistry.get('refresh');
            if (refreshMethod) {
              refreshMethod(data);
            }
            // Refresh functionality is handled by the host environment
          },
          
          // Standard method accessors with type safety
          getCurrentDataState: function() {
            const method = methodRegistry.get('getCurrentDataState');
            return method ? method() : undefined;
          },
          getDataStateHistory: function() {
            const method = methodRegistry.get('getDataStateHistory');
            return method ? method() : [];
          },
          validate: function() {
            const method = methodRegistry.get('validate');
            return method ? method() : true;
          },
          isDirty: function() {
            const method = methodRegistry.get('isDirty');
            return method ? method() : false;
          },
          reset: function() {
            const method = methodRegistry.get('reset');
            if (method) method();
          },
          scrollTo: function(target) {
            const method = methodRegistry.get('scrollTo');
            if (method) method(target);
          },
          focus: function(target) {
            const method = methodRegistry.get('focus');
            if (method) method(target);
          },
          
          // Generic method invoker for custom methods
          invokeMethod: function(methodName, ...args) {
            const method = methodRegistry.get(methodName);
            if (method) {
              return method(...args);
            }
            console.warn(\`[React-Runtime-JS] Method '\${methodName}' is not registered on component ${componentName}\`);
            return undefined;
          },
          
          // Check if a method exists
          hasMethod: function(methodName) {
            return methodRegistry.has(methodName);
          }
        };
      }
    `;
        return wrappedCode;
    }
    async loadRequiredLibraries(libraries, componentLibraries) {
        const loadedLibraries = new Map();
        if (this.config.debug) {
            console.log('🔍 loadRequiredLibraries called with:', {
                librariesCount: libraries?.length || 0,
                libraries: libraries?.map(l => ({ name: l.name, version: l.version, globalVariable: l.globalVariable }))
            });
        }
        if (!libraries || libraries.length === 0) {
            if (this.config.debug) {
                console.log('📚 No libraries to load, returning empty map');
            }
            return loadedLibraries;
        }
        if (typeof window === 'undefined') {
            console.warn('Library loading is only supported in browser environments');
            return loadedLibraries;
        }
        if (componentLibraries) {
            await LibraryRegistry.Config(false, componentLibraries);
        }
        else {
            console.warn('⚠️ No componentLibraries provided for LibraryRegistry initialization');
        }
        const filteredLibraries = libraries.filter(lib => {
            if (!lib || typeof lib !== 'object' || !lib.name) {
                console.warn(`⚠️ Invalid library entry detected (missing name):`, lib);
                return false;
            }
            if (lib.name === 'unknown' || lib.name === 'null' || lib.name === 'undefined') {
                console.warn(`⚠️ Filtering out invalid library with name '${lib.name}':`, lib);
                return false;
            }
            if (!lib.globalVariable || lib.globalVariable === 'undefined' || lib.globalVariable === 'null') {
                console.warn(`⚠️ Filtering out library '${lib.name}' with invalid globalVariable:`, lib.globalVariable);
                return false;
            }
            const libNameLower = lib.name.toLowerCase();
            if (libNameLower === 'react' || libNameLower === 'reactdom') {
                console.warn(`⚠️ Library '${lib.name}' is automatically loaded by the React runtime and should not be requested separately`);
                return false;
            }
            return true;
        });
        const libraryNames = filteredLibraries
            .map(lib => lib.name)
            .filter(name => name && typeof name === 'string');
        if (this.config.debug) {
            console.log('📦 Using dependency-aware loading for libraries:', libraryNames);
        }
        if (filteredLibraries.length === 0) {
            if (this.config.debug) {
                console.log('📚 All requested libraries were filtered out (React/ReactDOM), returning empty map');
            }
            return loadedLibraries;
        }
        try {
            const loadedLibraryMap = await LibraryLoader.loadLibrariesWithDependencies(libraryNames, componentLibraries, 'component-compiler', { debug: this.config.debug });
            for (const lib of filteredLibraries) {
                const isApproved = LibraryRegistry.isApproved(lib.name);
                if (!isApproved) {
                    console.error(`❌ Library '${lib.name}' is not approved`);
                    throw new Error(`Library '${lib.name}' is not approved. Only approved libraries can be used.`);
                }
                const loadedValue = loadedLibraryMap.get(lib.name);
                if (loadedValue) {
                    loadedLibraries.set(lib.globalVariable, loadedValue);
                    if (this.config.debug) {
                        console.log(`✅ Mapped ${lib.name} to global variable ${lib.globalVariable}`);
                    }
                }
                else {
                    const globalValue = window[lib.globalVariable];
                    if (globalValue) {
                        loadedLibraries.set(lib.globalVariable, globalValue);
                        if (this.config.debug) {
                            console.log(`✅ Found ${lib.name} already loaded as ${lib.globalVariable}`);
                        }
                    }
                    else {
                        console.error(`❌ Library '${lib.name}' failed to load`);
                        throw new Error(`Library '${lib.name}' failed to load or did not expose '${lib.globalVariable}'`);
                    }
                }
            }
        }
        catch (error) {
            console.error('Failed to load libraries with dependencies:', error);
            if (this.config.debug) {
                console.warn('⚠️ Falling back to non-dependency-aware loading due to error');
            }
            for (const lib of libraries) {
                if (window[lib.globalVariable]) {
                    loadedLibraries.set(lib.globalVariable, window[lib.globalVariable]);
                }
                else {
                    const libraryDef = LibraryRegistry.getLibrary(lib.name);
                    if (libraryDef) {
                        const resolvedVersion = LibraryRegistry.resolveVersion(lib.name, lib.version);
                        const cdnUrl = LibraryRegistry.getCdnUrl(lib.name, resolvedVersion);
                        if (cdnUrl) {
                            await this.loadScript(cdnUrl, lib.globalVariable);
                            const libraryValue = window[lib.globalVariable];
                            if (libraryValue) {
                                loadedLibraries.set(lib.globalVariable, libraryValue);
                            }
                        }
                    }
                }
            }
        }
        if (this.config.debug) {
            console.log(`✅ All libraries loaded successfully. Total: ${loadedLibraries.size}`);
            console.log('📚 Loaded libraries map:', Array.from(loadedLibraries.keys()));
        }
        return loadedLibraries;
    }
    async loadStyles(urls) {
        const loadPromises = urls.map(url => {
            return new Promise((resolve) => {
                const existingLink = document.querySelector(`link[href="${url}"]`);
                if (existingLink) {
                    resolve();
                    return;
                }
                const link = document.createElement('link');
                link.rel = 'stylesheet';
                link.href = url;
                document.head.appendChild(link);
                resolve();
            });
        });
        await Promise.all(loadPromises);
    }
    loadScript(url, globalName) {
        return new Promise((resolve, reject) => {
            const existingScript = document.querySelector(`script[src="${url}"]`);
            if (existingScript) {
                let attempts = 0;
                const maxAttempts = 50;
                const checkLoaded = () => {
                    if (window[globalName]) {
                        resolve();
                    }
                    else if (attempts >= maxAttempts) {
                        reject(new Error(`${globalName} not found after ${maxAttempts * 100}ms waiting for existing script`));
                    }
                    else {
                        attempts++;
                        setTimeout(checkLoaded, 100);
                    }
                };
                checkLoaded();
                return;
            }
            const script = document.createElement('script');
            script.src = url;
            script.async = true;
            script.onload = () => {
                let attempts = 0;
                const maxAttempts = 20;
                const checkInterval = 100;
                const checkGlobal = () => {
                    if (window[globalName]) {
                        if (this.config.debug) {
                            console.log(`  ✓ Global variable ${globalName} found after ${attempts * checkInterval}ms`);
                        }
                        resolve();
                    }
                    else if (attempts >= maxAttempts) {
                        if (this.config.debug) {
                            console.error(`  ❌ ${globalName} not found after ${attempts * checkInterval}ms`);
                            const matchingKeys = Object.keys(window).filter(k => k.toLowerCase().includes(globalName.toLowerCase()));
                            console.log(`  ℹ️ Matching window properties: ${matchingKeys.join(', ') || 'none'}`);
                        }
                        reject(new Error(`${globalName} not found after loading script from ${url}`));
                    }
                    else {
                        attempts++;
                        setTimeout(checkGlobal, checkInterval);
                    }
                };
                checkGlobal();
            };
            script.onerror = () => {
                reject(new Error(`Failed to load script: ${url}`));
            };
            document.head.appendChild(script);
        });
    }
    createComponentFactory(transpiledCode, componentName, loadedLibraries, options) {
        try {
            const factoryCreator = new Function('React', 'ReactDOM', 'useState', 'useEffect', 'useCallback', 'useMemo', 'useRef', 'useContext', 'useReducer', 'useLayoutEffect', 'libraries', 'styles', 'console', 'components', 'unwrapLibraryComponent', 'unwrapLibraryComponents', 'unwrapAllLibraryComponents', `${transpiledCode}; return createComponent;`);
            return (context, styles = {}, components = {}) => {
                const { React, ReactDOM, libraries = {} } = context;
                if (!React) {
                    console.error('🔴 CRITICAL: React is NULL in createComponentFactory!');
                    console.error('Context provided:', context);
                    console.error('Context keys:', Object.keys(context));
                    throw new Error('React is null in runtime context when creating component factory');
                }
                if (!React.useState || !React.useEffect) {
                    console.error('🔴 CRITICAL: React hooks are missing!');
                    console.error('React object keys:', React ? Object.keys(React) : 'React is null');
                    console.error('useState:', typeof React?.useState);
                    console.error('useEffect:', typeof React?.useEffect);
                }
                const mergedLibraries = { ...libraries };
                const specLibraryNames = new Set((options.libraries || []).map((lib) => lib.globalVariable).filter(Boolean));
                loadedLibraries.forEach((value, key) => {
                    if (specLibraryNames.has(key)) {
                        mergedLibraries[key] = value;
                    }
                    else if (this.config.debug) {
                        console.log(`⚠️ Filtering out dependency-only library: ${key}`);
                    }
                });
                const boundUnwrapLibraryComponent = (lib, name) => unwrapLibraryComponent(lib, name, this.config.debug);
                const boundUnwrapLibraryComponents = (lib, ...names) => unwrapLibraryComponents(lib, ...names, this.config.debug);
                const boundUnwrapAllLibraryComponents = (lib) => unwrapAllLibraryComponents(lib, this.config.debug);
                let createComponentFn;
                try {
                    createComponentFn = factoryCreator(React, ReactDOM, React.useState, React.useEffect, React.useCallback, React.useMemo, React.useRef, React.useContext, React.useReducer, React.useLayoutEffect, mergedLibraries, styles, console, components, boundUnwrapLibraryComponent, boundUnwrapLibraryComponents, boundUnwrapAllLibraryComponents);
                }
                catch (error) {
                    console.error('🔴 CRITICAL: Error calling factoryCreator with React hooks!');
                    console.error('Error:', error?.message || error);
                    console.error('React is:', React);
                    console.error('React type:', typeof React);
                    if (React) {
                        console.error('React.useState:', typeof React.useState);
                        console.error('React.useEffect:', typeof React.useEffect);
                    }
                    throw new Error(`Failed to create component factory: ${error?.message || error}`);
                }
                const Component = createComponentFn(React, ReactDOM, React.useState, React.useEffect, React.useCallback, React.useMemo, React.useRef, React.useContext, React.useReducer, React.useLayoutEffect, mergedLibraries, styles, console, components, boundUnwrapLibraryComponent, boundUnwrapLibraryComponents, boundUnwrapAllLibraryComponents);
                return Component;
            };
        }
        catch (error) {
            throw new Error(`Failed to create component factory: ${error.message}`);
        }
    }
    validateCompileOptions(options) {
        if (!options) {
            throw new Error('Component compilation failed: No options provided.\n' +
                'Expected an object with componentName and componentCode properties.\n' +
                'Example: { componentName: "MyComponent", componentCode: "function MyComponent() { ... }" }');
        }
        if (!options.componentName) {
            const providedKeys = Object.keys(options).join(', ');
            throw new Error('Component compilation failed: Component name is required.\n' +
                `Received options with keys: [${providedKeys}]\n` +
                'Please ensure your component spec includes a "name" property.\n' +
                'Example: { name: "MyComponent", code: "..." }');
        }
        if (!options.componentCode) {
            throw new Error(`Component compilation failed: Component code is required for "${options.componentName}".\n` +
                'Please ensure your component spec includes a "code" property with the component source code.\n' +
                'Example: { name: "MyComponent", code: "function MyComponent() { return <div>Hello</div>; }" }');
        }
        if (typeof options.componentCode !== 'string') {
            const actualType = typeof options.componentCode;
            throw new Error(`Component compilation failed: Component code must be a string for "${options.componentName}".\n` +
                `Received type: ${actualType}\n` +
                `Received value: ${JSON.stringify(options.componentCode).substring(0, 100)}...\n` +
                'Please ensure the code property contains a string of JavaScript/JSX code.');
        }
        if (options.componentCode.trim().length === 0) {
            throw new Error(`Component compilation failed: Component code is empty for "${options.componentName}".\n` +
                'The code property must contain valid JavaScript/JSX code defining a React component.');
        }
        if (!options.componentCode.includes(options.componentName)) {
            throw new Error(`Component compilation failed: Component code must define a component named "${options.componentName}".\n` +
                'The function/component name in the code must match the componentName property.\n' +
                `Expected to find: function ${options.componentName}(...) or const ${options.componentName} = ...\n` +
                'Code preview: ' + options.componentCode.substring(0, 200) + '...');
        }
    }
    generateComponentId(componentName) {
        return `${componentName}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    }
    getCachedComponent(componentName, code) {
        const cacheKey = this.createCacheKey(componentName, code);
        return this.compilationCache.get(cacheKey);
    }
    createCacheKey(componentName, code) {
        let hash = 0;
        for (let i = 0; i < code.length; i++) {
            const char = code.charCodeAt(i);
            hash = ((hash << 5) - hash) + char;
            hash = hash & hash;
        }
        return `${componentName}_${hash.toString(36)}`;
    }
    cacheComponent(component, code) {
        if (this.compilationCache.size >= this.config.maxCacheSize) {
            const firstKey = this.compilationCache.keys().next().value;
            if (firstKey)
                this.compilationCache.delete(firstKey);
        }
        const cacheKey = this.createCacheKey(component.name, code);
        this.compilationCache.set(cacheKey, component);
    }
    createCompilationError(error, componentName) {
        return {
            message: error.message || 'Unknown compilation error',
            stack: error.stack,
            componentName,
            phase: 'compilation',
            details: error
        };
    }
    clearCache() {
        this.compilationCache.clear();
    }
    getCacheSize() {
        return this.compilationCache.size;
    }
    updateConfig(config) {
        this.config = { ...this.config, ...config };
    }
}
//# sourceMappingURL=component-compiler.js.map