declare namespace webforms {
  type ReactCSSProperties = import('react').CSSProperties;
  type CraftComponent = import('@ws-ui/craftjs-core').SerializedNode;

  type ComponentProps<CSSProperties = ReactCSSProperties> = {
    disabled?: boolean;
    moveable?: boolean;
    deletable?: boolean;
    className?: string;
    role?: string;
    /**
     * A reference used to perform server side actions on the element based on a server call response.
     */
    serverSideRef?: string;
    /**
     * list of css properties that will be applied to the element by the user.
     */
    style?: CSSProperties;
    /**
     * Contains the list of events listeners that will be applied to the element during the runtime.
     */
    events?: WEvent[];
    /**
     * Contains list of classnames that have been applied to the element by the user
     */
    classNames?: string[];
    /**
     * Represants the main datasource for the component.
     *
     * It can contain multiple datasources paths separated by commas.
     *
     * Datasource Paths syntax: _`namespace`_ __:__ _`datasource.attribute1....attributeN`_
     */
    datasource?: string;
    /**
     * Represants the current element datasource for the component.
     *
     * It is usually used for items dealing with a list of items.
     *
     * It can only contain a single datasource path.
     *
     * Datasource Paths syntax: _`namespace`_ __:__ _`datasource.attribute1....attributeN`_
     */
    currentElement?: string;
    /**
     * Defines if the component is iterable.
     *
     * An iterable component must use the 'iterator' property.
     */
    iterable?: boolean;
    /**
     * @deprecated
     * Defines if the component is loopable.
     *
     * Used on Datatable component (which does not support the iterator property yet).
     */
    loopable?: boolean;
    /**
     * Represants the iterator key for the component.
     *
     * Used on components like Matrix & Select Box.
     */
    iterator?: string;
    /**
     * Defines if the component can be iterable as child.
     *
     * Used on sub-components of iterable components like Matrix & Select Box.
     */
    iterableChild?: boolean;
  };

  type Info = {
    displayName: string;
    icon?: React.FC;
    exposed?: boolean;
    isCanvas?: boolean;
    events: EventMeta[];
    iconName?: string;
    tipKey?: string;
    kind?: 'user' | 'basic' | 'template';
    sanityCheck?: {
      keys: {
        name: string | Array<ISanityCheckElement>;
        isDatasource: boolean;
        require: boolean;
      }[];
    };
  };

  type StyleClass = {
    /**
     * Unique id for the class.
     */
    id: string;
    /**
     * Scope of the classe.
     * values: 'shared', 'theme', 'local'
     */
    scope: 'shared' | 'theme' | 'local';
    /**
     * Name of the class
     */
    name: string;
    /**
     * content of the class.
     */
    content: string;
    /**
     * an id of the parent class. should be null if the class is not associated with any other class.
     */
    parentId: string | null;
    /**
     * An object of linked style classes.
     *
     * onDrop of the class on a component, if the component has a linked node,
     * it will be assigned a style class if it's type is declared in this object.
     *
     * key: represents the type of component to be associated with style class on drop.
     *
     * value: id of the associated style class.
     */
    children?: {
      [key: string]: string;
    };
    /**
     * defines the origin of the style class from which it was exported.
     */
    origin?: string;
  };

  type Datasources = datasources.ICreateDataSource[];

  type Metadata = Partial<{
    v: string;
    datasources: Datasources;
    styles: StyleClass[];
    title: string;
  }>;

  type Content = {
    components: Record<string, CraftComponent>;
    metadata?: Metadata;
  };

  // ------------------ EVENTS --------------------------
  type WEvent =
    | MemberFunctionEvent
    | NavigationEvent
    | SimpleActionEvent
    | DialogActionEvent;

  interface BaseEvent {
    id: string;
    events: string[];
    type: 'method' | 'navigation' | 'simple-action' | 'dialog';
    disabled?: boolean;
  }

  type MemberFunctionEvent = BaseEvent & {
    type: 'method';
    params: MethodParam[];
  } & Partial<{
      method: string;
      dataclass: string;
      returns: Omit<MethodParam, 'id'>;
      namespace: string;
      code: string;
      feedback: boolean;
      datasource: string;
      variadicType: string;
      methodType?: 'dataclass' | 'singleton';
      openIn: string;
      allowedOnHTTPGET?: boolean;
    }>;

  type WebformStateActionType = 'add' | 'delete' | 'clear';

  interface SimpleActionEvent extends BaseEvent {
    type: 'simple-action';
    datasource: {
      name: string;
      type?: datasources.ICreateDataSource['type'] | 'unknown';
      dataType?: datasources.ICreateDataSource['dataType'];
      namespace?: string;
      from?: string;
      target?: string;
      targetNamespace?: string;
      targetType?: string;
      iteratorDatasource?: ISplitDatasource;
      set?: {
        value?: string;
        type?: string;
      };
    };
    state?: Partial<{
      action: WebformStateActionType;
      states: string[];
      override: boolean;
    }>;
    action: string;
    actionType?: 'state' | 'datasource' | 'auth';
    query?: QueryString;
    orderBy?: OrderBy[];
    feedback?: {
      enabled?: boolean;
      messages?: { onSuccess?: string; onFail?: string };
    };
  }

  interface DialogActionEvent extends BaseEvent {
    type: 'dialog';
    actionType: 'open' | 'close';
    targetDialog: string;
  }

  interface NavigationEvent extends BaseEvent {
    type: 'navigation';
    parent: string;
    loader: string;
    target: string;
    externalLink: boolean;
    isHardCoded?: boolean;
  }

  interface EventMeta {
    label: string;
    value: string;
  }
  type HardCodedType =
    | 'date'
    | 'string'
    | 'object'
    | 'number'
    | 'bool'
    | 'array';
  type MethodParam = {
    id: string;
    name?: string;
    datasource?: string;
    type?: string;
    isHardCoded?: boolean;
    hardCodedType?: HardCodedTypes;
    hardCodedValue?: string;
  };

  type MethodReturn = Omit<MethodParam, 'name'>;

  interface QueryParam extends MethodParam {}

  interface OrderBy {
    name: string; // replace with attribute
    order: 'asc' | 'desc';
    id: string;
  }

  interface QueryString {
    query?: string; // query
    params?: QueryParam[];
  }
}
