import React, { type CSSProperties } from "react";
import type { ComponentNode, ComponentType } from '../types/component.types';
import { ComponentRegistry } from '../registry';
import type { RuntimeValues } from '../registry/types';
import { normalizeComponentStyles } from './styleNormalization';
import { useRuntimeOptional } from '../runtime';

interface ComponentRendererProps {
  component: ComponentNode;
  isSelected: string | null;
  lastModifiedId?: string | null;
  onSelect: (id: string) => void;
  renderChildren?: (children: ComponentNode[], parentType: ComponentType, parentStyles?: CSSProperties) => React.ReactNode;
  previewMode?: boolean;
  parentType?: ComponentType | null;
  parentStyles?: CSSProperties | null;
}

// Default no-op runtime values for when context is not available
const defaultRuntime: RuntimeValues = {
  state: { page: {}, global: {} },
  resolveText: (text: string) => text,
  executeHandlers: async () => { },
  dispatchEvent: async () => { },
  pages: [],
  navigateToPage: () => { },
  setStateValue: () => { },
};

export const ComponentRenderer: React.FC<ComponentRendererProps> = ({
  component,
  isSelected,
  lastModifiedId,
  onSelect,
  renderChildren,
  previewMode = false,
  parentType = null,
  parentStyles = null,
}) => {
  const isSelectedComponent = isSelected === component.id;
  const isModified = lastModifiedId === component.id;
  const domRef = React.useRef<HTMLDivElement>(null);

  // Get runtime context (may be null if not wrapped in provider)
  const runtimeContext = useRuntimeOptional();

  // Scroll into view and pulse when modified and selected (e.g. undo/redo)
  React.useEffect(() => {
    if (isSelectedComponent && isModified && !previewMode) {
      // Use requestAnimationFrame to ensure the DOM is ready (especially for restored components)
      requestAnimationFrame(() => {
        if (domRef.current) {
          domRef.current.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
          domRef.current.classList.remove('pulse-highlight');
          // Trigger reflow to restart animation
          void domRef.current.offsetWidth;
          domRef.current.classList.add('pulse-highlight');
        }
      });
    }
  }, [isSelectedComponent, isModified, previewMode]);

  // Normalize styles to prevent flexbox stretching, passing parent styles so the
  // normalizer can skip injection when the parent has explicit alignment intent.
  const normalizedStyles = normalizeComponentStyles(component.type, component.styles, parentType, parentStyles);
  const normalizedComponent = { ...component, styles: normalizedStyles };

  // Helper to render children with parent context.
  // We pass normalizedStyles so children can see this component's effective alignment.
  const renderChildrenWithContext = (children: ComponentNode[]) => {
    if (!renderChildren) return null;
    return renderChildren(children, component.type, normalizedStyles);
  };

  // Build runtime values from context or defaults
  const runtime: RuntimeValues = runtimeContext
    ? {
      state: runtimeContext.state,
      resolveText: runtimeContext.resolveText,
      executeHandlers: runtimeContext.executeHandlers,
      dispatchEvent: runtimeContext.dispatchEvent,
      pages: runtimeContext.pages,
      navigateToPage: runtimeContext.navigateToPage,
      setStateValue: runtimeContext.setStateValue,
    }
    : defaultRuntime;

  const renderComponent = () => {
    // Get component definition from registry
    const definition = ComponentRegistry.get(component.type);

    if (!definition) {
      console.warn(`Unknown component type: ${component.type}`);
      return null;
    }

    // Prepare children for containers
    const childrenContent = definition.canHaveChildren && renderChildren && component.children
      ? renderChildrenWithContext(component.children)
      : undefined;

    // Call the render function from the definition with runtime values
    return definition.render({
      component: normalizedComponent,
      isSelected: isSelectedComponent,
      onSelect,
      previewMode,
      children: childrenContent,
      runtime,
    });
  };

  if (previewMode) {
    return <>{renderComponent()}</>;
  }

  return (
    <div ref={domRef} style={{ display: 'contents' }}>
      {renderComponent()}
    </div>
  );
};
