import { mapProperties } from "./property-mapper.js";
import { getSyntaxPattern } from "./syntax-mapper.js";
import { ATOMIC_COMPONENTS_REGISTRY } from "./atomic-components-registry.js";
class BaseComponentGenerator {
  // Configuration
  config;
  adapter;
  // Architectural constraints
  MAX_DEPTH;
  ENABLE_WARNINGS;
  // Tracking
  warnings = [];
  imports = /* @__PURE__ */ new Set();
  constructor(adapter, config) {
    this.adapter = adapter;
    this.config = config;
    this.MAX_DEPTH = config.maxDepth ?? 3;
    this.ENABLE_WARNINGS = config.enableWarnings ?? true;
  }
  // ============================================================================
  // Public API
  // ============================================================================
  /**
   * Generate code for a complete view specification
   *
   * @param viewSpec - View specification from SpecVerse
   * @returns Generation result with code, imports, and warnings
   */
  generate(viewSpec) {
    this.reset();
    const importStatements = this.generateImports(viewSpec);
    const stateCode = viewSpec.state ? this.generateState(viewSpec.state) : "";
    const eventsCode = viewSpec.events ? this.generateEvents(viewSpec.events) : "";
    const componentsCode = this.generateComponentTree(viewSpec.components);
    const code = this.generateComponent({
      name: viewSpec.name,
      imports: importStatements,
      state: stateCode,
      events: eventsCode,
      components: componentsCode
    });
    return {
      code,
      imports: Array.from(this.imports),
      warnings: this.warnings
    };
  }
  // ============================================================================
  // Shared Component Rendering (Framework-Agnostic)
  // ============================================================================
  /**
   * Render all components in the view
   */
  generateComponentTree(components) {
    const rendered = Object.entries(components).map(([name, component]) => {
      return this.renderComponent(component, {
        depth: 0,
        path: [name],
        dataContext: void 0
      });
    });
    return rendered.join("\n\n");
  }
  /**
   * Render a single component with depth tracking and nesting enforcement
   *
   * This is the core shared logic - applies to ALL frameworks
   */
  renderComponent(component, context) {
    if (context.depth > this.MAX_DEPTH) {
      this.addWarning(
        `Component at path ${context.path.join(".")} exceeds max depth (${this.MAX_DEPTH}). Flattening to maintain readability.`
      );
      return this.renderFlattened(component, context);
    }
    const componentDef = ATOMIC_COMPONENTS_REGISTRY[component.type];
    if (!componentDef) {
      this.addWarning(`Unknown component type: ${component.type}`);
      return `<!-- Unknown component: ${component.type} -->`;
    }
    const mappedProps = this.mapComponentProperties(component, componentDef);
    if (component.condition) {
      return this.renderConditional(component, mappedProps, context);
    }
    if (component.dataSource) {
      return this.renderList(component, mappedProps, context);
    }
    const children = component.children ? this.renderChildren(component.children, context) : void 0;
    return this.renderAdapterComponent(
      component.type,
      mappedProps,
      children,
      context
    );
  }
  /**
   * Map component properties using property-mapper
   */
  mapComponentProperties(component, componentDef) {
    if (!component.properties) {
      return {};
    }
    return mapProperties(
      component.type,
      component.properties,
      this.config.target
    );
  }
  /**
   * Render child components with incremented depth
   */
  renderChildren(children, parentContext) {
    const childContext = {
      ...parentContext,
      depth: parentContext.depth + 1
    };
    return children.map((child, index) => {
      const childPath = [...parentContext.path, `child_${index}`];
      return this.renderComponent(child, {
        ...childContext,
        path: childPath
      });
    }).join("\n");
  }
  /**
   * Render conditional component using syntax-mapper
   */
  renderConditional(component, mappedProps, context) {
    const innerComponent = this.renderAdapterComponent(
      component.type,
      mappedProps,
      component.children ? this.renderChildren(component.children, context) : void 0,
      context
    );
    return getSyntaxPattern("conditionalRender", this.config.framework, {
      condition: component.condition,
      Component: this.getComponentName(component.type),
      props: this.formatProps(mappedProps)
    });
  }
  /**
   * Render list (loop) component using syntax-mapper
   */
  renderList(component, mappedProps, context) {
    const itemName = this.getItemName(component.dataSource);
    const keyProperty = this.getKeyProperty(component);
    const childContext = {
      ...context,
      depth: context.depth + 1,
      dataContext: itemName
    };
    return getSyntaxPattern("loopRender", this.config.framework, {
      array: component.dataSource,
      item: itemName,
      key: keyProperty,
      Component: this.getComponentName(component.type)
    });
  }
  /**
   * Flatten component when depth exceeded
   *
   * Extracts nested children into sibling components to reduce nesting
   */
  renderFlattened(component, context) {
    const componentDef = ATOMIC_COMPONENTS_REGISTRY[component.type];
    const mappedProps = this.mapComponentProperties(component, componentDef);
    const flatComponent = this.renderAdapterComponent(
      component.type,
      mappedProps,
      void 0,
      // No children
      context
    );
    const flattenedChildren = component.children ? component.children.map((child, index) => {
      return this.renderComponent(child, {
        depth: context.depth,
        // Same depth (sibling)
        path: [...context.path, `flattened_${index}`]
      });
    }).join("\n") : "";
    return flatComponent + "\n" + flattenedChildren;
  }
  /**
   * Delegate to adapter for actual component rendering
   */
  renderAdapterComponent(type, properties, children, context) {
    const adapterComponent = this.adapter.components[type];
    if (!adapterComponent) {
      this.addWarning(`Adapter missing component: ${type}`);
      return `<!-- Missing adapter for: ${type} -->`;
    }
    return adapterComponent.render({
      properties,
      children
    });
  }
  // ============================================================================
  // Helper Methods
  // ============================================================================
  /**
   * Get component name for import/usage
   */
  getComponentName(type) {
    const componentDef = ATOMIC_COMPONENTS_REGISTRY[type];
    return componentDef?.name || type.charAt(0).toUpperCase() + type.slice(1);
  }
  /**
   * Get item variable name for loop rendering
   */
  getItemName(dataSource) {
    if (dataSource.endsWith("s")) {
      return dataSource.slice(0, -1);
    }
    return dataSource + "Item";
  }
  /**
   * Get key property for list items
   */
  getKeyProperty(component) {
    return component.properties?.keyProperty || "id";
  }
  /**
   * Format properties for inline rendering
   */
  formatProps(properties) {
    return Object.entries(properties).map(([key, value]) => {
      if (typeof value === "string") {
        return `${key}="${value}"`;
      }
      return `${key}={${JSON.stringify(value)}}`;
    }).join(" ");
  }
  /**
   * Add warning message
   */
  addWarning(message) {
    if (this.ENABLE_WARNINGS) {
      this.warnings.push(message);
    }
  }
  /**
   * Reset generator state for new generation
   */
  reset() {
    this.warnings = [];
    this.imports = /* @__PURE__ */ new Set();
  }
  /**
   * Add import statement
   */
  addImport(importStatement) {
    this.imports.add(importStatement);
  }
}
function validateNestingDepth(component, maxDepth = 3) {
  const issues = [];
  function calculateDepth(comp, currentDepth) {
    if (!comp.children || comp.children.length === 0) {
      return currentDepth;
    }
    const childDepths = comp.children.map(
      (child) => calculateDepth(child, currentDepth + 1)
    );
    return Math.max(...childDepths);
  }
  const actualDepth = calculateDepth(component, 0);
  if (actualDepth > maxDepth) {
    issues.push(
      `Component nesting depth (${actualDepth}) exceeds maximum (${maxDepth})`
    );
  }
  return {
    valid: actualDepth <= maxDepth,
    actualDepth,
    issues
  };
}
function extractComponentTypes(components) {
  const types = /* @__PURE__ */ new Set();
  function walk(component) {
    types.add(component.type);
    if (component.children) {
      component.children.forEach(walk);
    }
  }
  Object.values(components).forEach(walk);
  return types;
}
function countComponents(components) {
  let count = 0;
  function walk(component) {
    count++;
    if (component.children) {
      component.children.forEach(walk);
    }
  }
  Object.values(components).forEach(walk);
  return count;
}
export {
  BaseComponentGenerator,
  countComponents,
  extractComponentTypes,
  validateNestingDepth
};
