import React, { createElement, useState, useMemo } from "react";
import {
  BaseComponentGenerator
} from "../shared/base-generator.js";
import { mapProperties } from "../shared/property-mapper.js";
import { getComponentMetadata } from "../shared/component-metadata.js";
class RuntimeViewRenderer extends BaseComponentGenerator {
  runtimeConfig;
  viewContext;
  constructor(adapter, config) {
    super(adapter, config);
    this.runtimeConfig = config;
  }
  // ============================================================================
  // Public API - Runtime Rendering
  // ============================================================================
  /**
   * Render view as React element (runtime)
   *
   * @param viewSpec - View specification
   * @param context - Runtime context (state, data, handlers)
   * @returns React element
   */
  renderRuntime(viewSpec, context) {
    this.viewContext = this.initializeContext(viewSpec, context);
    const components = this.renderComponentsRuntime(viewSpec.components);
    return createElement(
      "div",
      { className: "specverse-runtime-view", "data-view": viewSpec.name },
      components
    );
  }
  /**
   * Create a React component from view spec
   *
   * Returns a React component function that can be used directly
   *
   * @param viewSpec - View specification
   * @returns React component function
   */
  createRuntimeComponent(viewSpec) {
    const renderer = this;
    return function RuntimeViewComponent(props) {
      const [state, setState] = useState(
        () => renderer.initializeState(viewSpec.state)
      );
      const handlers = useMemo(
        () => renderer.createEventHandlers(viewSpec.events, state, setState),
        [state]
      );
      const context = {
        state,
        setState: (updates) => setState((prev) => ({ ...prev, ...updates })),
        handlers,
        data: props.data || {}
      };
      return renderer.renderRuntime(viewSpec, context);
    };
  }
  // ============================================================================
  // Abstract Method Implementations (Not Used in Runtime)
  // ============================================================================
  generateImports(viewSpec) {
    return "";
  }
  generateComponent(parts) {
    return "";
  }
  generateState(state) {
    return "";
  }
  generateEvents(events) {
    return "";
  }
  getFileExtension() {
    return "";
  }
  getAdditionalFiles(viewSpec) {
    return {};
  }
  // ============================================================================
  // Runtime-Specific Methods
  // ============================================================================
  /**
   * Initialize runtime context
   */
  initializeContext(viewSpec, context) {
    return {
      state: context?.state || this.initializeState(viewSpec.state),
      setState: context?.setState || (() => {
      }),
      handlers: context?.handlers || this.createEventHandlers(viewSpec.events),
      data: context?.data || {}
    };
  }
  /**
   * Initialize state from view spec
   */
  initializeState(state) {
    if (!state) return {};
    const initialState = {};
    for (const [name, def] of Object.entries(state)) {
      initialState[name] = def.initial;
    }
    return initialState;
  }
  /**
   * Create event handlers from view spec
   */
  createEventHandlers(events, state, setState) {
    if (!events) return {};
    const handlers = {};
    for (const [name, def] of Object.entries(events)) {
      handlers[`handle${this.capitalize(name)}`] = (...args) => {
        if (this.runtimeConfig.debug) {
          console.log(`[RuntimeView] Event: ${name}`, args);
        }
        try {
          const fn = new Function("state", "setState", "args", def.body);
          fn(state, setState, args);
        } catch (error) {
          console.error(`[RuntimeView] Event handler error (${name}):`, error);
        }
      };
    }
    return handlers;
  }
  /**
   * Render components as React elements
   */
  renderComponentsRuntime(components) {
    return Object.entries(components).map(
      ([name, component]) => this.renderComponentRuntime(component, {
        depth: 0,
        path: [name]
      })
    );
  }
  /**
   * Render single component as React element
   */
  renderComponentRuntime(component, context) {
    if (context.depth > this.MAX_DEPTH) {
      if (this.runtimeConfig.debug) {
        console.warn(`[RuntimeView] Max depth exceeded at ${context.path.join(".")}`);
      }
      return null;
    }
    const metadata = getComponentMetadata(component.type);
    if (!metadata) {
      console.warn(`[RuntimeView] Unknown component type: ${component.type}`);
      return null;
    }
    const mappedProps = component.properties ? mapProperties(component.type, component.properties, "runtime") : {};
    const props = {
      ...mappedProps,
      key: context.path.join("-")
    };
    if (component.condition && this.viewContext) {
      const condition = this.evaluateCondition(component.condition, this.viewContext);
      if (!condition) return null;
    }
    if (component.dataSource && this.viewContext) {
      return this.renderListRuntime(component, props, context);
    }
    let children = null;
    if (component.children && component.children.length > 0) {
      children = component.children.map(
        (child, index) => this.renderComponentRuntime(child, {
          ...context,
          depth: context.depth + 1,
          path: [...context.path, `child_${index}`]
        })
      );
    }
    const adapterComponent = this.adapter.components[component.type];
    if (!adapterComponent) {
      console.warn(`[RuntimeView] No adapter for component: ${component.type}`);
      return null;
    }
    return this.createElementFromAdapter(component.type, props, children);
  }
  /**
   * Render list of items
   */
  renderListRuntime(component, props, context) {
    if (!this.viewContext) return null;
    const dataArray = this.viewContext.data[component.dataSource];
    if (!Array.isArray(dataArray)) {
      console.warn(`[RuntimeView] Data source not found: ${component.dataSource}`);
      return null;
    }
    const items = dataArray.map((item, index) => {
      const itemProps = {
        ...props,
        ...item,
        key: `${context.path.join("-")}-${index}`
      };
      return this.createElementFromAdapter(component.type, itemProps, null);
    });
    return createElement(React.Fragment, null, ...items);
  }
  /**
   * Create React element from adapter component
   */
  createElementFromAdapter(type, props, children) {
    return createElement(
      "div",
      {
        ...props,
        className: `specverse-runtime-${type} ${props.className || ""}`.trim(),
        "data-component": type
      },
      children
    );
  }
  /**
   * Evaluate condition expression
   */
  evaluateCondition(condition, context) {
    try {
      const fn = new Function("state", "data", `return ${condition}`);
      return fn(context.state, context.data);
    } catch (error) {
      console.error(`[RuntimeView] Condition evaluation error:`, error);
      return false;
    }
  }
  /**
   * Capitalize first letter
   */
  capitalize(str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
  }
}
function createRuntimeRenderer(adapter, config) {
  const defaultConfig = {
    framework: "runtime",
    target: "runtime",
    liveReload: false,
    debug: false,
    maxDepth: 3,
    enableWarnings: true
  };
  const finalConfig = { ...defaultConfig, ...config };
  return new RuntimeViewRenderer(adapter, finalConfig);
}
function renderView(viewSpec, adapter, context) {
  const renderer = createRuntimeRenderer(adapter);
  return renderer.renderRuntime(viewSpec, context);
}
function createViewComponent(viewSpec, adapter) {
  const renderer = createRuntimeRenderer(adapter);
  return renderer.createRuntimeComponent(viewSpec);
}
export {
  RuntimeViewRenderer,
  createRuntimeRenderer,
  createViewComponent,
  renderView
};
