import "reflect-metadata";
import { IClassConstructor, ITypeRegistryRenderer } from '../types';
/**
 * Creates a property decorator that stores metadata without making the property readonly
   @template MetadataType - The type of the metadata
   @template PropertyKeyType - The type of the property key
 * @param metadataKey - The key to store the metadata under
   @param metadata - The metadata to store, or a function that returns the metadata
 * @returns PropertyDecorator
 */
export declare function createPropertyDecorator<MetadataType = any, PropertyKeyType extends string | symbol | number = any>(metadataKey: any, 
/**
    Retrieves the metadata for a property
    @param {Object} target - The class constructor
    @param {PropertyKeyType} propertyKey - The property key
    @param {MetadataType} existingMetaData - The existing metadata for the property
    @param {Record<PropertyKeyType, MetadataType>} allExistingMetadata - All existing metadata for the class
    @returns {MetadataType} The metadata for the property
    
*/
metadata: ((existingMetaData: MetadataType, allExistingMetadata: Record<PropertyKeyType, MetadataType>, target: Object, propertyKey: any) => MetadataType) | MetadataType): PropertyDecorator;
/**
 * Retrieves all properties of a class that have been decorated with a specific metadata key.
   @template MetaDataType - The type of the metadata
   @template PropertyKeyType - The type of the property key
 * @param target The class to retrieve decorated properties from.
 * @param metadataKey The metadata key.
 * @returns Record of property names and their metadata
 */
export declare function getDecoratedProperties<MetaDataType = any, PropertyKeyType extends string | symbol | number = any>(target: IClassConstructor, metadataKey: any): Record<PropertyKeyType, MetaDataType>;
/**
 * Retrieves metadata for a specific property.
 * @template MetaDataType - The type of the metadata
 * @param target - target The class or object containing the property.
 * @param metadataKey - The key to retrieve metadata for
  *@param propertyKey - The name of the propertyfor which metadata is being retrieved.
 * @returns {MetaDataType} The metadata value for the property.
 */
export declare function getDecoratedProperty<MetaDataType = any>(target: IClassConstructor, metadataKey: any, propertyKey: any): MetaDataType;
/**
 * @class TypeRegistry
 *
 * A utility class responsible for registering and managing custom renderers for various types of components.
 *
 * This class supports extensibility by allowing external users to register their own renderers
 * for different components, such as `datagridCell` or `formField`. It uses a centralized registry
 * to map types (e.g., 'number', 'string', 'date') to rendering functions.
 *
 * The `TypeRegistry` is primarily designed to help render components dynamically based on the value's type
 * and the component type. It makes use of internal registries to store and retrieve these renderers
 * based on the context.

 * It's allows external users to register custom renderers for specific value types
 * (e.g., 'number', 'string') and component types (e.g., 'datagridCell', 'formField'). These renderers
 * can then be retrieved and used to render dynamic content in components.
 *
 * The class makes use of a centralized registry to store and retrieve renderers for various contexts,
 * ensuring that each component type has its own set of renderers.
  This implementation uses Reflect Metadata to store and retrieve renderers efficiently.
 *
 * ## Example Usage:
 *
 * ```typescript
 * // Register a number renderer for datagrid cells
 * TypeRegistry.register('number', 'datagridCell', (value: number) => {
 *   return `<div class="cell number">${value}</div>`;
 * });
 *
 * // Render a number cell
 * const numberCell = TypeRegistry.getRenderer('number', 'datagridCell');
 * console.log(numberCell?.(123)); // Output: <div class="cell number">123</div>
 *
 * // Register a text renderer for form fields
 * TypeRegistry.register('text', 'formField', (value: string) => {
 *   return `<input type="text" value="${value}" />`;
 * });
 *
 * // Render a form text field
 * const textField = TypeRegistry.getRenderer('text', 'formField');
 * console.log(textField?.('Hello World')); // Output: <input type="text" value="Hello World" />
 * ```
 */
export declare class TypeRegistry {
    private static getMetadataKey;
    /**
     * Registers a new renderer for a specific value type and component type.
     *
     * This method allows users to extend the system by adding their own custom renderers for various types.
     * For example, you can register a renderer for numbers in a datagrid or a custom input field for forms.
     *
      @template InputType - The type of the value to be rendered.
      @template OutputType - The type of output that the rendering function will produce.
     * @param {string} type - The value type (e.g., 'number', 'string', 'date').
     * @param {string} componentType - The component type (e.g., 'datagridCell', 'formField').
     * @param {ITypeRegistryRenderer<InputType,OutputType>} renderer - The function that renders the value as an HTML string.
     *
     * ## Example:
     *
     * ```typescript
     * TypeRegistry.register('number', 'datagridCell', (value: number) => {
     *   return `<div class="cell number">${value}</div>`;
     * });
     * ```
     */
    static register<InputType = any, OutputType = any>(type: string, componentType: string, renderer: ITypeRegistryRenderer<InputType, OutputType>): void;
    /**
     * Retrieves a registered renderer for a specific value type and component type.
     *
     * This method allows users to fetch a renderer for a particular type (e.g., 'number', 'string')
     * and component type (e.g., `datagridCell`, `formField`), which can then be used to render values dynamically.
     *
     * @template InputType - The type of the value that the renderer handles.
       @template OutputType - The type of output that the rendering function will produce.
     * @param {string} type - The value type (e.g., 'number', 'string', 'date').
     * @param {string} componentType - The component type (e.g., 'datagridCell', 'formField').
     * @returns {ITypeRegistryRenderer<InputType,OuputType> | undefined} - The renderer function if found, or `undefined` if no renderer is registered.
     *
     * ## Example:
     *
     * ```typescript
     * const renderer = TypeRegistry.getRenderer('number', 'datagridCell');
     * if (renderer) {
     *   const html = renderer(123);
     *   console.log(html);  // Output: <div class="cell number">123</div>
     * }
     * ```
     */
    static getRenderer<InputType = any, OutputType = any>(type: string, componentType: string): ITypeRegistryRenderer<InputType, OutputType> | undefined;
    /**
     * Checks if a renderer exists for a specific value type and component type.
     *
     * This method can be used to verify whether a renderer is registered for a given type
     * and component before attempting to render content dynamically.
     *
     * @param {string} type - The value type (e.g., 'number', 'string').
     * @param {string} componentType - The component type (e.g., 'datagridCell', 'formField').
     * @returns {boolean} - Returns `true` if a renderer is found, otherwise `false`.
     *
     * ## Example:
     *
     * ```typescript
     * const hasRenderer = TypeRegistry.hasRenderer('number', 'datagridCell');
     * console.log(hasRenderer); // Output: true or false depending on if a renderer exists
     * ```
     */
    static hasRenderer(type: string, componentType: string): boolean;
    /**
   * Renders a component based on its registered type and value.
   *
     @template InputType - The type of the value that the renderer handles.
     @template OutputType - The type of output that the rendering function will produce.
   * @param type - The type of the value (e.g., 'number', 'string').
   * @param value - The value to be rendered.
   * @param componentType - The type of component being rendered (e.g., 'datagridCell', 'formField').
     @param fallbackValue - The value to be rendered if no renderer is found.
   * @returns {OutputType}.The rendered content
   */
    static render<InputType = any, OutputType = any>(type: string, value: InputType, componentType: string, fallbackValue?: OutputType): OutputType;
}
/**
 * A decorator factory that registers a rendering function for a specific type and component.
 *
 * This function creates a decorator that can be applied to a rendering function,
 * allowing the user to register that function with the `TypeRegistry` under a specific
 * type and component type. This makes it easy to extend rendering capabilities for
 * different components dynamically.
 *
 * @template InputType - The type of input that the rendering function will accept.
 * @template OutputType - The type of output that the rendering function will produce.
 *
 * @param {string} componentType - The type of component being registered (e.g., 'datagridCell', 'formField').
 * @returns {function(type: string): function(target: ITypeRegistryRenderer<InputType, OutputType>): void} -
 * A decorator function that accepts the type and registers the rendering function.
 *
 * ## Example:
 *
 * ```typescript
 * // Create a number renderer for datagrid cells
 * const numberRenderer: ITypeRegistryRenderer<number, string> = (value) => {
 *   return `<div class="cell number">${value}</div>`;
 * };
 *
 * // Use the decorator to register the renderer
 * @createTypeRegistryDecorator<number, string>('datagridCell')('number')
 * class NumberCellRenderer {
 *   render(value: number): string {
 *     return numberRenderer(value);
 *   }
 * }
 *
 * // The number renderer can now be used in a datagrid
 * const renderer = TypeRegistry.getRenderer('number', 'datagridCell');
 * console.log(renderer(123)); // Output: <div class="cell number">123</div>
 * ```
 */
export declare function createTypeRegistryDecorator<InputType = any, OutputType = any>(componentType: string): (type: string) => (target: ITypeRegistryRenderer<InputType, OutputType>) => void;
/**
 * The `ComponentRegistry` class is a dynamic registry system that associates renderers (functions)
 * with specific component names. It allows you to register and retrieve renderers for various components
 * based on their names, making it easier to decouple the rendering logic from the components themselves.
 * This is especially useful in cases where different components may require distinct rendering behavior
 * for different types of data.
 *
 * The renderers are stored using Reflect metadata, enabling the system to dynamically resolve and invoke
 * the appropriate renderer without hard-coding logic for each component.
 *
 * ### Key Features:
 * - **Dynamic Registration**: Register renderers for specific components at runtime.
 * - **Flexible Rendering**: Retrieve and apply the correct renderer based on component name.
 * - **Type-Safe**: Generic types `InputType` and `OutputType` allow for strong typing of the renderer functions.
 * - **Fallback Mechanism**: Provide a fallback value when no renderer is found for a given component name.
 *
 * ### Use Cases:
 *
 * #### 1. Custom UI Rendering Based on Component Types
 * In UI applications, components can have different rendering logic for different data types.
 * For example, rendering numbers differently from dates. The `ComponentRegistry` allows you to register
 * specific renderers for these different components and render them based on their types.
 *
 * ```ts
 * // Register a renderer for handling numbers
 * ComponentRegistry.register<number, string>("numberRenderer", (input: number) => {
 *   return `Formatted Number: ${input.toFixed(2)}`;
 * });
 *
 * // Register a renderer for handling dates
 * ComponentRegistry.register<Date, string>("dateRenderer", (input: Date) => {
 *   return `Formatted Date: ${input.toDateString()}`;
 * });
 *
 * // Render a number using the registered number renderer
 * const renderedNumber = ComponentRegistry.render(123.456, "numberRenderer");
 * console.log(renderedNumber); // Outputs: "Formatted Number: 123.46"
 *
 * // Render a date using the registered date renderer
 * const renderedDate = ComponentRegistry.render(new Date(2024, 9, 15), "dateRenderer");
 * console.log(renderedDate); // Outputs: "Formatted Date: Mon Oct 15 2024"
 * ```
 *
 * #### 2. Fallback Rendering for Unregistered Components
 * In cases where a renderer is not registered for a given component, you can provide a fallback value.
 * This ensures that your application can handle missing renderers gracefully.
 *
 * ```ts
 * // Render with a fallback when no renderer is registered for the component
 * const renderedValue = ComponentRegistry.render(42, "unknownRenderer", "Fallback: No renderer found");
 * console.log(renderedValue); // Outputs: "Fallback: No renderer found"
 *
 * // Register a renderer for text components later on
 * ComponentRegistry.register<string, string>("textRenderer", (input: string) => {
 *   return `Text: ${input.toUpperCase()}`;
 * });
 *
 * // Render the text component after registration
 * const renderedText = ComponentRegistry.render("hello", "textRenderer", "Default text");
 * console.log(renderedText); // Outputs: "Text: HELLO"
 * ```
 *
 * #### 3. Conditional Rendering for Complex Components
 * For applications with multiple components that require different renderers depending on conditions
 * (e.g., dashboard widgets, form elements), the `ComponentRegistry` can dynamically choose which renderer
 * to use at runtime.
 *
 * ```ts
 * // Register a renderer for number widgets
 * ComponentRegistry.register<number, string>("widgetNumberRenderer", (input: number) => {
 *   return `Widget Number: ${input}`;
 * });
 *
 * // Register a renderer for string widgets
 * ComponentRegistry.register<string, string>("widgetStringRenderer", (input: string) => {
 *   return `Widget String: ${input}`;
 * });
 *
 * // Use conditional rendering based on component names
 * const widgetData = { type: "widgetNumberRenderer", value: 25 };
 * const renderedWidget = ComponentRegistry.render(widgetData.value, widgetData.type, "Default Widget");
 * console.log(renderedWidget); // Outputs: "Widget Number: 25"
 * ```
 *
 * The `ComponentRegistry` provides an elegant and scalable solution for managing rendering logic across
 * various types of components, enabling flexible and maintainable code.
 */
export declare class ComponentRegistry {
    /**
     * Constructs the metadata key used for storing component renderers.
     *
     * @param componentName - The name of the component for which the metadata key is generated.
     * If not provided, defaults to `"undefined-component-name"`.
     * @returns The generated metadata key string, in the format `COMPONENT_REGISTRY_KEY:componentName`.
     *
     * @example
     * ```ts
     * const key = ComponentRegistry.getMetadataKey("myComponent");
     * // key would be something like "COMPONENT_REGISTRY_KEY:myComponent"
     * ```
     */
    private static getMetadataKey;
    /**
     * Registers a renderer for a specific component by its name.
     * The renderer is stored using Reflect metadata and can be retrieved later for rendering specific values.
     *
     * @typeParam InputType - The type of the input value that the renderer will handle.
     * @typeParam OutputType - The type of the output value produced by the renderer.
     * @param componentName - The name of the component to register the renderer for. Must be a non-empty string.
     * @param renderer - A function that takes an input of `InputType` and returns an output of `OutputType`.
     *
     * @example
     * ```ts
     * ComponentRegistry.register<number, string>("numberRenderer", (input: number) => `The number is ${input}`);
     * ```
     */
    static register<InputType = any, OutputType = any>(componentName: string, renderer: ITypeRegistryRenderer<InputType, OutputType>): void;
    /**
     * Retrieves the renderer function for a specific component by its name.
     *
     * @typeParam InputType - The type of the input value that the renderer handles.
     * @typeParam OutputType - The type of the output value produced by the renderer.
     * @param componentName - The name of the component whose renderer is being retrieved.
     * @returns The renderer function, if one is registered for the component, otherwise `undefined`.
     *
     * @example
     * ```ts
     * const renderer = ComponentRegistry.getRenderer<number, string>("numberRenderer");
     * if (renderer) {
     *   console.log(renderer(42)); // Outputs: "The number is 42"
     * }
     * ```
     */
    static getRenderer<InputType = any, OutputType = any>(componentName: string): ITypeRegistryRenderer<InputType, OutputType> | undefined;
    /**
     * Checks if a renderer is registered for a given component name.
     *
     * @param componentName - The name of the component to check.
     * @returns `true` if a renderer is registered for the component, otherwise `false`.
     *
     * @example
     * ```ts
     * const hasRenderer = ComponentRegistry.hasRenderer("numberRenderer");
     * console.log(hasRenderer); // Outputs: true or false
     * ```
     */
    static hasRenderer(componentName: string): boolean;
    /**
     * Renders a value using the registered renderer for the specified component.
     * If no renderer is found, it returns the `fallbackValue` (if provided).
     *
     * @typeParam InputType - The type of the input value to be rendered.
     * @typeParam OutputType - The type of the output value produced by the renderer.
     * @param value - The input value to be rendered by the component's renderer.
     * @param componentName - The name of the component whose renderer will process the input value.
     * @param fallbackValue - (Optional) A value to return if no renderer is registered for the component.
     * @returns The output value produced by the renderer, or the `fallbackValue` if no renderer is registered.
     *
     * @example
     * ```ts
     * const output = ComponentRegistry.render(42, "numberRenderer", "No renderer available");
     * console.log(output); // Outputs: "The number is 42" or "No renderer available" if the renderer isn't registered
     * ```
     */
    static render<InputType = any, OutputType = any>(value: InputType, componentName: string, fallbackValue?: OutputType): OutputType;
}
/**
 * Creates a decorator that registers a rendering function for a specified component in the `ComponentRegistry`.
 * This allows the decorated function to be automatically registered as a renderer for the given component name.
 *
 * The decorator can be applied to any function or class that matches the signature of the `ITypeRegistryRenderer<InputType, OutputType>`.
 * This is useful for associating a specific component renderer with a component name without manually calling `ComponentRegistry.register()`.
 *
 * ### Example Usage:
 *
 * #### 1. Registering a String Renderer
 *
 * ```ts
 * // Create a string renderer decorator for the component "stringRenderer"
 * const StringRenderer = createComponentRegistryDecorator<string, string>("stringRenderer");
 *
 * // Apply the decorator to a string rendering function
 * @StringRenderer
 * function renderString(input: string): string {
 *   return `Formatted String: ${input.toUpperCase()}`;
 * }
 *
 * // Use the ComponentRegistry to render a string using the registered function
 * const renderedString = ComponentRegistry.render("hello world", "stringRenderer");
 * console.log(renderedString); // Outputs: "Formatted String: HELLO WORLD"
 * ```
 *
 * #### 2. Registering a Date Renderer
 *
 * ```ts
 * // Create a date renderer decorator for the component "dateRenderer"
 * const DateRenderer = createComponentRegistryDecorator<Date, string>("dateRenderer");
 *
 * // Apply the decorator to a date rendering function
 * @DateRenderer
 * function renderDate(input: Date): string {
 *   return `Formatted Date: ${input.toISOString()}`;
 * }
 *
 * // Use the registered renderer for dates
 * const renderedDate = ComponentRegistry.render(new Date(), "dateRenderer");
 * console.log(renderedDate); // Outputs: "Formatted Date: 2024-10-15T12:00:00.000Z" (example output)
 * ```
 *
 * @typeParam InputType - The type of the input value that the renderer handles.
 * @typeParam OutputType - The type of the output value produced by the renderer.
 * @param componentName - The name of the component to register the renderer for.
 * @returns A decorator function that registers the target function as a renderer in the `ComponentRegistry`.
 */
export declare function createComponentRegistryDecorator<InputType = any, OutputType = any>(componentName: string): (target: ITypeRegistryRenderer<InputType, OutputType>) => void;
